xref: /minix/minix/lib/libc/sys/ioctl.c (revision 9f988b79)
1 #include <sys/cdefs.h>
2 #include "namespace.h"
3 #include <lib.h>
4 #include <stdarg.h>
5 
6 #include <sys/ioctl.h>
7 #include <minix/i2c.h>
8 #include <string.h>
9 #include <sys/ioccom.h>
10 #include <stdarg.h>
11 #include <fcntl.h>
12 
13 static void rewrite_i2c_netbsd_to_minix(minix_i2c_ioctl_exec_t *out,
14     i2c_ioctl_exec_t *in);
15 static void rewrite_i2c_minix_to_netbsd(i2c_ioctl_exec_t *out,
16     minix_i2c_ioctl_exec_t *in);
17 
18 static void rewrite_i2c_netbsd_to_minix(minix_i2c_ioctl_exec_t *out,
19 	i2c_ioctl_exec_t *in)
20 {
21   memset(out, '\0', sizeof(minix_i2c_ioctl_exec_t));
22 
23   out->iie_op = in->iie_op;
24   out->iie_addr = in->iie_addr;
25   out->iie_cmdlen = I2C_EXEC_MAX_CMDLEN < in->iie_cmdlen ?
26   	I2C_EXEC_MAX_CMDLEN : in->iie_cmdlen;
27   out->iie_buflen = I2C_EXEC_MAX_BUFLEN < in->iie_buflen ?
28   	I2C_EXEC_MAX_BUFLEN : in->iie_buflen;
29 
30   if (in->iie_cmdlen > 0 && in->iie_cmd != NULL) {
31 	memcpy(out->iie_cmd, in->iie_cmd, in->iie_cmdlen);
32   }
33 
34   if (in->iie_buflen > 0 && in->iie_buf != NULL) {
35 	memcpy(out->iie_buf, in->iie_buf, in->iie_buflen);
36   }
37 }
38 
39 static void rewrite_i2c_minix_to_netbsd(i2c_ioctl_exec_t *out,
40 	minix_i2c_ioctl_exec_t *in)
41 {
42   /* the only field that changes is iie_buf, everything else is the same */
43   if (in->iie_buflen > 0 ) {
44 	memcpy(out->iie_buf, in->iie_buf, in->iie_buflen);
45   }
46 }
47 
48 /*
49  * Library implementation of FIOCLEX and FIONCLEX.
50  */
51 static int
52 ioctl_to_setfd(int fd, int mask, int val)
53 {
54 	int fl;
55 
56 	if ((fl = fcntl(fd, F_GETFD)) == -1)
57 		return -1;
58 
59 	fl = (fl & ~mask) | val;
60 
61 	return fcntl(fd, F_SETFD, fl);
62 }
63 
64 /*
65  * Library implementation of FIONBIO and FIOASYNC.
66  */
67 static int
68 ioctl_to_setfl(int fd, void * data, int sfl)
69 {
70 	int arg, fl;
71 
72 	arg = *(int *)data;
73 
74 	if ((fl = fcntl(fd, F_GETFL)) == -1)
75 		return -1;
76 
77 	if (arg)
78 		fl |= sfl;
79 	else
80 		fl &= ~sfl;
81 
82 	return fcntl(fd, F_SETFL, fl & ~O_ACCMODE);
83 }
84 
85 /*
86  * Library implementation of various deprecated IOCTLs.  These particular IOCTL
87  * calls change how the file descriptors behave, and have nothing to do with
88  * the actual open file.  They should therefore be handled by VFS rather than
89  * individual device drivers.  We rewrite them to use fcntl(2) instead here.
90  */
91 static int
92 ioctl_to_fcntl(int fd, unsigned long request, void * data)
93 {
94 	switch (request) {
95 	case FIOCLEX:
96 		return ioctl_to_setfd(fd, FD_CLOEXEC, FD_CLOEXEC);
97 	case FIONCLEX:
98 		return ioctl_to_setfd(fd, FD_CLOEXEC, 0);
99 	case FIONBIO:
100 		return ioctl_to_setfl(fd, data, O_NONBLOCK);
101 	case FIOASYNC:
102 		return ioctl_to_setfl(fd, data, O_ASYNC);
103 	case FIOSETOWN: /* XXX TODO */
104 	case FIOGETOWN: /* XXX TODO */
105 	default:
106 		errno = ENOTTY;
107 		return -1;
108 	}
109 }
110 
111 int     ioctl(int fd, unsigned long request, ...)
112 {
113   int r, request_save;
114   message m;
115   vir_bytes addr;
116   void *data;
117   va_list ap;
118 
119   va_start(ap, request);
120   data = va_arg(ap, void *);
121   va_end(ap);
122 
123   /*
124    * To support compatibility with interfaces on other systems, certain
125    * requests are re-written to flat structures (i.e. without pointers).
126    */
127   minix_i2c_ioctl_exec_t i2c;
128 
129   request_save = request;
130 
131   switch (request) {
132 	case FIOCLEX:
133 	case FIONCLEX:
134 	case FIONBIO:
135 	case FIOASYNC:
136 	case FIOSETOWN:
137 	case FIOGETOWN:
138 		return ioctl_to_fcntl(fd, request, data);
139 
140 	case I2C_IOCTL_EXEC:
141 		rewrite_i2c_netbsd_to_minix(&i2c, data);
142 		addr = (vir_bytes) &i2c;
143 		request = MINIX_I2C_IOCTL_EXEC;
144 		break;
145 	default:
146 		/* Keep original as-is */
147 		addr = (vir_bytes)data;
148 		break;
149   }
150 
151   memset(&m, 0, sizeof(m));
152   m.m_lc_vfs_ioctl.fd = fd;
153   m.m_lc_vfs_ioctl.req = request;
154   m.m_lc_vfs_ioctl.arg = addr;
155 
156   r = _syscall(VFS_PROC_NR, VFS_IOCTL, &m);
157 
158   /* Translate back to original form */
159   switch (request_save) {
160 	case I2C_IOCTL_EXEC:
161 		rewrite_i2c_minix_to_netbsd(data, &i2c);
162 		break;
163 	default:
164 		/* Nothing to do */
165 		break;
166   }
167 
168   return r;
169 }
170