summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2013-03-05 19:13:31 +0100
committerDavid Herrmann <dh.herrmann@gmail.com>2013-03-05 19:13:31 +0100
commite668e9b6cc241d430a26a604ed9ada1737a63d8a (patch)
treeff9b7274d57373fa4e385de30ef8736505a73ebf
parent4307d9baf1fa22357572a097d5646ea14e493d36 (diff)
uvt: client: implement major ioctl callbacks
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>
-rw-r--r--src/uvt.h101
-rw-r--r--src/uvt_client.c257
2 files changed, 272 insertions, 86 deletions
diff --git a/src/uvt.h b/src/uvt.h
index b9f49f6..a69dd6f 100644
--- 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, ...);
*/
};
diff --git a/src/uvt_client.c b/src/uvt_client.c
index b58eb0b..d31a35b 100644
--- a/src/uvt_client.c
+++ b/src/uvt_client.c
@@ -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;