uvt: client: implement major ioctl callbacks
authorDavid Herrmann <dh.herrmann@gmail.com>
Tue, 5 Mar 2013 18:13:31 +0000 (19:13 +0100)
committerDavid Herrmann <dh.herrmann@gmail.com>
Tue, 5 Mar 2013 18:13:31 +0000 (19:13 +0100)
Add callbacks for all major ioctls. We currently only implement ioctls
that are used by xserver on linux machines. Feel free to implement the new
ioctls.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
src/uvt.h
src/uvt_client.c

index b9f49f6..a69dd6f 100644 (file)
--- a/src/uvt.h
+++ b/src/uvt.h
@@ -70,28 +70,6 @@ struct uvt_tty_ops {
        int (*read) (void *data, uint8_t *mem, size_t len);
        int (*write) (void *data, const uint8_t *mem, size_t len);
        unsigned int (*poll) (void *data);
-
-/*
-       int (*ioctl_TIOCPKT) (void *data, ...);
-       int (*ioctl_TCFLSH) (void *data, long arg);
-       int (*ioctl_TCXONC) (void *data, ...);
-       int (*ioctl_TCGETS) (void *data, struct termios *arg);
-       int (*ioctl_TCSETS) (void *data, const struct termios *arg);
-       int (*ioctl_TCSETSF) (void *data, const struct termios *arg);
-       int (*ioctl_TCSETSW) (void *data, const struct termios *arg);
-       int (*ioctl_TCGETA) (void *data, ...);
-       int (*ioctl_TCSETA) (void *data, ...);
-       int (*ioctl_TCSETAF) (void *data, ...);
-       int (*ioctl_TCSETAW) (void *data, ...);
-       int (*ioctl_TIOCGLCKTRMIOS) (void *data, ...);
-       int (*ioctl_TIOCSLCKTRMIOS) (void *data, ...);
-       int (*ioctl_TCGETX) (void *data, ...);
-       int (*ioctl_TCSETX) (void *data, ...);
-       int (*ioctl_TCSETXW) (void *data, ...);
-       int (*ioctl_TCSETXF) (void *data, ...);
-       int (*ioctl_TIOCGSOFTCAR) (void *data, ...);
-       int (*ioctl_TIOCSSOFTCAR) (void *data, ...);
-*/
 };
 
 /* virtual terminals */
@@ -121,7 +99,55 @@ struct uvt_vt_ops {
        int (*write) (void *data, const uint8_t *mem, size_t len);
        unsigned int (*poll) (void *data);
 
+       /* TTY ioctls */
+       int (*ioctl_TCFLSH) (void *data, unsigned long arg);
+
+       /* VT ioctls */
+       int (*ioctl_VT_ACTIVATE) (void *data, unsigned long arg);
+       int (*ioctl_VT_WAITACTIVE) (void *data, unsigned long arg);
+       int (*ioctl_VT_GETSTATE) (void *data, struct vt_stat *arg);
+       int (*ioctl_VT_OPENQRY) (void *data, unsigned int *arg);
+       int (*ioctl_VT_GETMODE) (void *data, struct vt_mode *arg);
+       int (*ioctl_VT_SETMODE) (void *data, const struct vt_mode *arg);
+       int (*ioctl_VT_RELDISP) (void *data, unsigned long arg);
+       int (*ioctl_KDGETMODE) (void *data, unsigned int *arg);
+       int (*ioctl_KDSETMODE) (void *data, unsigned int arg);
+       int (*ioctl_KDGKBMODE) (void *data, unsigned int *arg);
+       int (*ioctl_KDSKBMODE) (void *data, unsigned int arg);
+
 /*
+   Complete list of all ioctls that the kernel supports. The internal handler
+   returns -EOPNOTSUPP for all of them as they haven't been implemented, yet.
+   We need to check if they are actually required or whether it's not worth the
+   effort.
+   Please implement them only if you know a client that requires them. Also
+   consider implementing them as a no-op if the client doesn't depend on the
+   call to actually do something. We want to keep the actual callbacks at a
+   minimum.
+
+   TTY ioctls
+
+       int (*ioctl_TIOCPKT) (void *data, ...);
+       int (*ioctl_TCXONC) (void *data, ...);
+       int (*ioctl_TCGETS) (void *data, struct termios *arg);
+       int (*ioctl_TCSETS) (void *data, const struct termios *arg);
+       int (*ioctl_TCSETSF) (void *data, const struct termios *arg);
+       int (*ioctl_TCSETSW) (void *data, const struct termios *arg);
+       int (*ioctl_TCGETA) (void *data, ...);
+       int (*ioctl_TCSETA) (void *data, ...);
+       int (*ioctl_TCSETAF) (void *data, ...);
+       int (*ioctl_TCSETAW) (void *data, ...);
+       int (*ioctl_TIOCGLCKTRMIOS) (void *data, ...);
+       int (*ioctl_TIOCSLCKTRMIOS) (void *data, ...);
+       int (*ioctl_TCGETX) (void *data, ...);
+       int (*ioctl_TCSETX) (void *data, ...);
+       int (*ioctl_TCSETXW) (void *data, ...);
+       int (*ioctl_TCSETXF) (void *data, ...);
+       int (*ioctl_TIOCGSOFTCAR) (void *data, ...);
+       int (*ioctl_TIOCSSOFTCAR) (void *data, ...);
+
+   VT ioctls
+
        int (*ioctl_TIOCLINUX) (void *data, ...);
        int (*ioctl_KIOCSOUND) (void *data, ...);
        int (*ioctl_KDMKTONE) (void *data, ...);
@@ -131,12 +157,8 @@ struct uvt_vt_ops {
        int (*ioctl_KDENABIO) (void *data);
        int (*ioctl_KDDISABIO) (void *data);
        int (*ioctl_KDKBDREP) (void *data, struct kbd_repeat *arg);
-       int (*ioctl_KDGETMODE) (void *data, long *arg);
-       int (*ioctl_KDSETMODE) (void *data, long arg);
        int (*ioctl_KDMAPDISP) (void *data);
        int (*ioctl_KDUNMAPDISP) (void *data);
-       int (*ioctl_KDGKBMODE) (void *data, long *arg);
-       int (*ioctl_KDSKBMODE) (void *data, long arg);
        int (*ioctl_KDGKBMETA) (void *data, long *arg);
        int (*ioctl_KDSKBMETA) (void *data, long arg);
        int (*ioctl_KDGETKEYCODE) (void *data, ...);
@@ -154,14 +176,7 @@ struct uvt_vt_ops {
        int (*ioctl_KDGKBLED) (void *data, char *arg);
        int (*ioctl_KDSKBLED) (void *data, long arg);
        int (*ioctl_KDSIGACCEPT) (void *data, ...);
-       int (*ioctl_VT_GETMODE) (void *data, struct vt_mode *arg);
-       int (*ioctl_VT_SETMODE) (void *data, const struct vt_mode *arg);
-       int (*ioctl_VT_GETSTATE) (void *data, struct vt_stat *arg);
-       int (*ioctl_VT_OPENQRY) (void *data, int *arg);
-       int (*ioctl_VT_ACTIVATE) (void *data, long arg);
        int (*ioctl_VT_SETACTIVATE) (void *data, ...);
-       int (*ioctl_VT_WAITACTIVE) (void *data, long arg);
-       int (*ioctl_VT_RELDISP) (void *data, long arg);
        int (*ioctl_VT_DISALLOCATE) (void *data, ...);
        int (*ioctl_VT_RESIZE) (void *data, ...);
        int (*ioctl_VT_RESIZEX) (void *data, ...);
@@ -184,26 +199,6 @@ struct uvt_vt_ops {
        int (*ioctl_VT_UNLOCKSWITCH) (void *data);
        int (*ioctl_VT_GETHIFONTMASK) (void *data, ...);
        int (*ioctl_VT_WAITEVENT) (void *data, ...);
-
-       int (*ioctl_TIOCPKT) (void *data, ...);
-       int (*ioctl_TCFLSH) (void *data, long arg);
-       int (*ioctl_TCXONC) (void *data, ...);
-       int (*ioctl_TCGETS) (void *data, struct termios *arg);
-       int (*ioctl_TCSETS) (void *data, const struct termios *arg);
-       int (*ioctl_TCSETSF) (void *data, const struct termios *arg);
-       int (*ioctl_TCSETSW) (void *data, const struct termios *arg);
-       int (*ioctl_TCGETA) (void *data, ...);
-       int (*ioctl_TCSETA) (void *data, ...);
-       int (*ioctl_TCSETAF) (void *data, ...);
-       int (*ioctl_TCSETAW) (void *data, ...);
-       int (*ioctl_TIOCGLCKTRMIOS) (void *data, ...);
-       int (*ioctl_TIOCSLCKTRMIOS) (void *data, ...);
-       int (*ioctl_TCGETX) (void *data, ...);
-       int (*ioctl_TCSETX) (void *data, ...);
-       int (*ioctl_TCSETXW) (void *data, ...);
-       int (*ioctl_TCSETXF) (void *data, ...);
-       int (*ioctl_TIOCGSOFTCAR) (void *data, ...);
-       int (*ioctl_TIOCSSOFTCAR) (void *data, ...);
 */
 };
 
index b58eb0b..d31a35b 100644 (file)
@@ -814,7 +814,12 @@ void uvt_client_ll_ioctl(fuse_req_t req, int cmd, void *arg,
                         const void *in_buf, size_t in_bufsz, size_t out_bufsz)
 {
        struct uvt_client *client = (void*)(uintptr_t)fi->fh;
+       uintptr_t uarg = (uintptr_t)arg;
        bool compat;
+       int ret;
+       struct vt_stat vtstat;
+       struct vt_mode vtmode;
+       unsigned int uval;
 
        if (!client) {
                fuse_reply_err(req, EINVAL);
@@ -835,6 +840,225 @@ void uvt_client_ll_ioctl(fuse_req_t req, int cmd, void *arg,
        }
 
        switch (cmd) {
+
+       /* TTY ioctls */
+
+       case TCFLSH:
+               if (ioctl_param(req, arg, 0, in_bufsz, 0, out_bufsz))
+                       return;
+               if (!client->vt->ioctl_TCFLSH) {
+                       fuse_reply_err(req, EOPNOTSUPP);
+               } else {
+                       ret = client->vt->ioctl_TCFLSH(client->vt_data,
+                                                      (unsigned long)uarg);
+                       if (ret)
+                               fuse_reply_err(req, abs(ret));
+                       else
+                               fuse_reply_ioctl(req, 0, NULL, 0);
+               }
+               break;
+
+       case TIOCPKT:
+       case TCXONC:
+       case TCGETS:
+       case TCSETS:
+       case TCSETSF:
+       case TCSETSW:
+       case TCGETA:
+       case TCSETA:
+       case TCSETAF:
+       case TCSETAW:
+       case TIOCGLCKTRMIOS:
+       case TIOCSLCKTRMIOS:
+       case TCGETX:
+       case TCSETX:
+       case TCSETXW:
+       case TCSETXF:
+       case TIOCGSOFTCAR:
+       case TIOCSSOFTCAR:
+               fuse_reply_err(req, EOPNOTSUPP);
+               break;
+
+       /* VT ioctls */
+
+       case VT_ACTIVATE:
+               if (ioctl_param(req, arg, 0, in_bufsz, 0, out_bufsz))
+                       return;
+               if (!client->vt->ioctl_VT_ACTIVATE) {
+                       fuse_reply_err(req, EOPNOTSUPP);
+               } else {
+                       ret = client->vt->ioctl_VT_ACTIVATE(client->vt_data,
+                                                       (unsigned long)uarg);
+                       if (ret)
+                               fuse_reply_err(req, abs(ret));
+                       else
+                               fuse_reply_ioctl(req, 0, NULL, 0);
+               }
+               break;
+
+       case VT_WAITACTIVE:
+               if (ioctl_param(req, arg, 0, in_bufsz, 0, out_bufsz))
+                       return;
+               if (!client->vt->ioctl_VT_WAITACTIVE) {
+                       fuse_reply_err(req, EOPNOTSUPP);
+               } else {
+                       ret = client->vt->ioctl_VT_WAITACTIVE(client->vt_data,
+                                                       (unsigned long)uarg);
+                       if (ret)
+                               fuse_reply_err(req, abs(ret));
+                       else
+                               fuse_reply_ioctl(req, 0, NULL, 0);
+               }
+               break;
+
+       case VT_GETSTATE:
+               if (ioctl_param(req, arg, 0, in_bufsz,
+                               sizeof(struct vt_stat), out_bufsz))
+                       return;
+               if (!client->vt->ioctl_VT_GETSTATE) {
+                       fuse_reply_err(req, EOPNOTSUPP);
+               } else {
+                       memset(&vtstat, 0, sizeof(vtstat));
+                       ret = client->vt->ioctl_VT_GETSTATE(client->vt_data,
+                                                           &vtstat);
+                       if (ret)
+                               fuse_reply_err(req, abs(ret));
+                       else
+                               fuse_reply_ioctl(req, 0, &vtstat,
+                                                sizeof(vtstat));
+               }
+               break;
+
+       case VT_OPENQRY:
+               if (ioctl_param(req, arg, 0, in_bufsz,
+                               sizeof(unsigned int), out_bufsz))
+                       return;
+               if (!client->vt->ioctl_VT_OPENQRY) {
+                       fuse_reply_err(req, EOPNOTSUPP);
+               } else {
+                       uval = 0;
+                       ret = client->vt->ioctl_VT_OPENQRY(client->vt_data,
+                                                          &uval);
+                       if (ret)
+                               fuse_reply_err(req, abs(ret));
+                       else
+                               fuse_reply_ioctl(req, 0, &uval, sizeof(uval));
+               }
+               break;
+
+       case VT_GETMODE:
+               if (ioctl_param(req, arg, 0, in_bufsz,
+                               sizeof(struct vt_mode), out_bufsz))
+                       return;
+               if (!client->vt->ioctl_VT_GETMODE) {
+                       fuse_reply_err(req, EOPNOTSUPP);
+               } else {
+                       memset(&vtmode, 0, sizeof(vtmode));
+                       ret = client->vt->ioctl_VT_GETMODE(client->vt_data,
+                                                          &vtmode);
+                       if (ret)
+                               fuse_reply_err(req, abs(ret));
+                       else
+                               fuse_reply_ioctl(req, 0, &vtmode,
+                                                sizeof(vtmode));
+               }
+               break;
+
+       case VT_SETMODE:
+               if (ioctl_param(req, arg, sizeof(struct vt_mode), in_bufsz,
+                               0, out_bufsz))
+                       return;
+               if (!client->vt->ioctl_VT_SETMODE) {
+                       fuse_reply_err(req, EOPNOTSUPP);
+               } else {
+                       ret = client->vt->ioctl_VT_SETMODE(client->vt_data,
+                                               (const struct vt_mode*)in_buf);
+                       if (ret)
+                               fuse_reply_err(req, abs(ret));
+                       else
+                               fuse_reply_ioctl(req, 0, NULL, 0);
+               }
+               break;
+
+       case VT_RELDISP:
+               if (ioctl_param(req, arg, 0, in_bufsz, 0, out_bufsz))
+                       return;
+               if (!client->vt->ioctl_VT_RELDISP) {
+                       fuse_reply_err(req, EOPNOTSUPP);
+               } else {
+                       ret = client->vt->ioctl_VT_RELDISP(client->vt_data,
+                                                       (unsigned long)uarg);
+                       if (ret)
+                               fuse_reply_err(req, abs(ret));
+                       else
+                               fuse_reply_ioctl(req, 0, NULL, 0);
+               }
+               break;
+
+       case KDGETMODE:
+               if (ioctl_param(req, arg, 0, in_bufsz,
+                               sizeof(unsigned int), out_bufsz))
+                       return;
+               if (!client->vt->ioctl_KDGETMODE) {
+                       fuse_reply_err(req, EOPNOTSUPP);
+               } else {
+                       uval = 0;
+                       ret = client->vt->ioctl_KDGETMODE(client->vt_data,
+                                                         &uval);
+                       if (ret)
+                               fuse_reply_err(req, abs(ret));
+                       else
+                               fuse_reply_ioctl(req, 0, &uval, sizeof(uval));
+               }
+               break;
+
+       case KDSETMODE:
+               if (ioctl_param(req, arg, 0, in_bufsz, 0, out_bufsz))
+                       return;
+               if (!client->vt->ioctl_KDSETMODE) {
+                       fuse_reply_err(req, EOPNOTSUPP);
+               } else {
+                       ret = client->vt->ioctl_KDSETMODE(client->vt_data,
+                                                       (unsigned int)uarg);
+                       if (ret)
+                               fuse_reply_err(req, abs(ret));
+                       else
+                               fuse_reply_ioctl(req, 0, NULL, 0);
+               }
+               break;
+
+       case KDGKBMODE:
+               if (ioctl_param(req, arg, 0, in_bufsz,
+                               sizeof(unsigned int), out_bufsz))
+                       return;
+               if (!client->vt->ioctl_KDGKBMODE) {
+                       fuse_reply_err(req, EOPNOTSUPP);
+               } else {
+                       uval = 0;
+                       ret = client->vt->ioctl_KDGKBMODE(client->vt_data,
+                                                         &uval);
+                       if (ret)
+                               fuse_reply_err(req, abs(ret));
+                       else
+                               fuse_reply_ioctl(req, 0, &uval, sizeof(uval));
+               }
+               break;
+
+       case KDSKBMODE:
+               if (ioctl_param(req, arg, 0, in_bufsz, 0, out_bufsz))
+                       return;
+               if (!client->vt->ioctl_KDSKBMODE) {
+                       fuse_reply_err(req, EOPNOTSUPP);
+               } else {
+                       ret = client->vt->ioctl_KDSKBMODE(client->vt_data,
+                                                       (unsigned int)uarg);
+                       if (ret)
+                               fuse_reply_err(req, abs(ret));
+                       else
+                               fuse_reply_ioctl(req, 0, NULL, 0);
+               }
+               break;
+
        case TIOCLINUX:
        case KIOCSOUND:
        case KDMKTONE:
@@ -844,12 +1068,8 @@ void uvt_client_ll_ioctl(fuse_req_t req, int cmd, void *arg,
        case KDENABIO:
        case KDDISABIO:
        case KDKBDREP:
-       case KDGETMODE:
-       case KDSETMODE:
        case KDMAPDISP:
        case KDUNMAPDISP:
-       case KDGKBMODE:
-       case KDSKBMODE:
        case KDGKBMETA:
        case KDSKBMETA:
        case KDGETKEYCODE:
@@ -867,14 +1087,7 @@ void uvt_client_ll_ioctl(fuse_req_t req, int cmd, void *arg,
        case KDGKBLED:
        case KDSKBLED:
        case KDSIGACCEPT:
-       case VT_GETMODE:
-       case VT_SETMODE:
-       case VT_GETSTATE:
-       case VT_OPENQRY:
-       case VT_ACTIVATE:
        case VT_SETACTIVATE:
-       case VT_WAITACTIVE:
-       case VT_RELDISP:
        case VT_DISALLOCATE:
        case VT_RESIZE:
        case VT_RESIZEX:
@@ -899,28 +1112,6 @@ void uvt_client_ll_ioctl(fuse_req_t req, int cmd, void *arg,
        case VT_WAITEVENT:
                fuse_reply_err(req, EOPNOTSUPP);
                break;
-
-       case TIOCPKT:
-       case TCFLSH:
-       case TCXONC:
-       case TCGETS:
-       case TCSETS:
-       case TCSETSF:
-       case TCSETSW:
-       case TCGETA:
-       case TCSETA:
-       case TCSETAF:
-       case TCSETAW:
-       case TIOCGLCKTRMIOS:
-       case TIOCSLCKTRMIOS:
-       case TCGETX:
-       case TCSETX:
-       case TCSETXW:
-       case TCSETXF:
-       case TIOCGSOFTCAR:
-       case TIOCSSOFTCAR:
-               fuse_reply_err(req, EOPNOTSUPP);
-               break;
        default:
                fuse_reply_err(req, EINVAL);
                break;