restricted ia64 patches to ia64 again, they still break builds on
[linux-flexiantxendom0-3.2.10.git] / arch / ia64 / ia32 / ia32_ioctl.c
1 /*
2  * IA32 Architecture-specific ioctl shim code
3  *
4  * Copyright (C) 2000 VA Linux Co
5  * Copyright (C) 2000 Don Dugger <n0ano@valinux.com>
6  * Copyright (C) 2001-2002 Hewlett-Packard Co
7  *      David Mosberger-Tang <davidm@hpl.hp.com>
8  */
9
10 #include <linux/types.h>
11 #include <linux/dirent.h>
12 #include <linux/fs.h>           /* argh, msdos_fs.h isn't self-contained... */
13
14 #include <linux/msdos_fs.h>
15 #include <linux/mtio.h>
16 #include <linux/ncp_fs.h>
17 #include <linux/capi.h>
18 #include <linux/videodev.h>
19 #include <linux/synclink.h>
20 #include <linux/atmdev.h>
21 #include <linux/atm_eni.h>
22 #include <linux/atm_nicstar.h>
23 #include <linux/atm_zatm.h>
24 #include <linux/atm_idt77105.h>
25 #include <linux/ppp_defs.h>
26 #include <linux/if_ppp.h>
27 #include <linux/ixjuser.h>
28 #include <linux/i2o-dev.h>
29 #include <scsi/scsi.h>
30 /* Ugly hack. */
31 #undef  __KERNEL__
32 #include <scsi/scsi_ioctl.h>
33 #define __KERNEL__
34 #include <scsi/sg.h>
35
36 #include <asm/ia32.h>
37
38 #include <../drivers/char/drm/drm.h>
39 #include <../drivers/char/drm/mga_drm.h>
40 #include <../drivers/char/drm/i810_drm.h>
41
42
43 #define IOCTL_NR(a)     ((a) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))
44
45 #define DO_IOCTL(fd, cmd, arg) ({                       \
46         int _ret;                                       \
47         mm_segment_t _old_fs = get_fs();                \
48                                                         \
49         set_fs(KERNEL_DS);                              \
50         _ret = sys_ioctl(fd, cmd, (unsigned long)arg);  \
51         set_fs(_old_fs);                                \
52         _ret;                                           \
53 })
54
55 #define P(i)    ((void *)(unsigned long)(i))
56
57 asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
58
59 static long
60 put_dirent32 (struct dirent *d, struct linux32_dirent *d32)
61 {
62         size_t namelen = strlen(d->d_name);
63
64         return (put_user(d->d_ino, &d32->d_ino)
65                 || put_user(d->d_off, &d32->d_off)
66                 || put_user(d->d_reclen, &d32->d_reclen)
67                 || copy_to_user(d32->d_name, d->d_name, namelen + 1));
68 }
69 /*
70  *  The transform code for the SG_IO ioctl was brazenly lifted from
71  *  the Sparc64 port in the file `arch/sparc64/kernel/ioctl32.c'.
72  *  Thanks to Jakub Jelinek & Eddie C. Dost.
73  */
74 typedef struct sg_io_hdr32 {
75         int interface_id;       /* [i] 'S' for SCSI generic (required) */
76         int dxfer_direction;    /* [i] data transfer direction  */
77         char  cmd_len;          /* [i] SCSI command length ( <= 16 bytes) */
78         char  mx_sb_len;                /* [i] max length to write to sbp */
79         short iovec_count;      /* [i] 0 implies no scatter gather */
80         int dxfer_len;          /* [i] byte count of data transfer */
81         int dxferp;             /* [i], [*io] points to data transfer memory
82                                               or scatter gather list */
83         int cmdp;               /* [i], [*i] points to command to perform */
84         int sbp;                /* [i], [*o] points to sense_buffer memory */
85         int timeout;            /* [i] MAX_UINT->no timeout (unit: millisec) */
86         int flags;              /* [i] 0 -> default, see SG_FLAG... */
87         int pack_id;            /* [i->o] unused internally (normally) */
88         int usr_ptr;            /* [i->o] unused internally */
89         char  status;           /* [o] scsi status */
90         char  masked_status;    /* [o] shifted, masked scsi status */
91         char  msg_status;       /* [o] messaging level data (optional) */
92         char  sb_len_wr;        /* [o] byte count actually written to sbp */
93         short host_status;      /* [o] errors from host adapter */
94         short driver_status;    /* [o] errors from software driver */
95         int resid;              /* [o] dxfer_len - actual_transferred */
96         int duration;           /* [o] time taken by cmd (unit: millisec) */
97         int info;               /* [o] auxiliary information */
98 } sg_io_hdr32_t;  /* 64 bytes long (on IA32) */
99
100 static int alloc_sg_iovec(sg_io_hdr_t *sgp, int uptr32)
101 {
102         struct compat_iovec *uiov = (struct compat_iovec *) P(uptr32);
103         sg_iovec_t *kiov;
104         int i;
105
106         sgp->dxferp = kmalloc(sgp->iovec_count *
107                               sizeof(sg_iovec_t), GFP_KERNEL);
108         if (!sgp->dxferp)
109                 return -ENOMEM;
110         memset(sgp->dxferp, 0,
111                sgp->iovec_count * sizeof(sg_iovec_t));
112
113         kiov = (sg_iovec_t *) sgp->dxferp;
114         for (i = 0; i < sgp->iovec_count; i++) {
115                 int iov_base32;
116                 if (__get_user(iov_base32, &uiov->iov_base) ||
117                     __get_user(kiov->iov_len, &uiov->iov_len))
118                         return -EFAULT;
119
120                 kiov->iov_base = kmalloc(kiov->iov_len, GFP_KERNEL);
121                 if (!kiov->iov_base)
122                         return -ENOMEM;
123                 if (copy_from_user(kiov->iov_base,
124                                    (void *) P(iov_base32),
125                                    kiov->iov_len))
126                         return -EFAULT;
127
128                 uiov++;
129                 kiov++;
130         }
131
132         return 0;
133 }
134
135 static int copy_back_sg_iovec(sg_io_hdr_t *sgp, int uptr32)
136 {
137         struct compat_iovec *uiov = (struct compat_iovec *) P(uptr32);
138         sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
139         int i;
140
141         for (i = 0; i < sgp->iovec_count; i++) {
142                 int iov_base32;
143
144                 if (__get_user(iov_base32, &uiov->iov_base))
145                         return -EFAULT;
146
147                 if (copy_to_user((void *) P(iov_base32),
148                                  kiov->iov_base,
149                                  kiov->iov_len))
150                         return -EFAULT;
151
152                 uiov++;
153                 kiov++;
154         }
155
156         return 0;
157 }
158
159 static void free_sg_iovec(sg_io_hdr_t *sgp)
160 {
161         sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
162         int i;
163
164         for (i = 0; i < sgp->iovec_count; i++) {
165                 if (kiov->iov_base) {
166                         kfree(kiov->iov_base);
167                         kiov->iov_base = NULL;
168                 }
169                 kiov++;
170         }
171         kfree(sgp->dxferp);
172         sgp->dxferp = NULL;
173 }
174
175 static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
176 {
177         sg_io_hdr32_t *sg_io32;
178         sg_io_hdr_t sg_io64;
179         int dxferp32, cmdp32, sbp32;
180         mm_segment_t old_fs;
181         int err = 0;
182
183         sg_io32 = (sg_io_hdr32_t *)arg;
184         err = __get_user(sg_io64.interface_id, &sg_io32->interface_id);
185         err |= __get_user(sg_io64.dxfer_direction, &sg_io32->dxfer_direction);
186         err |= __get_user(sg_io64.cmd_len, &sg_io32->cmd_len);
187         err |= __get_user(sg_io64.mx_sb_len, &sg_io32->mx_sb_len);
188         err |= __get_user(sg_io64.iovec_count, &sg_io32->iovec_count);
189         err |= __get_user(sg_io64.dxfer_len, &sg_io32->dxfer_len);
190         err |= __get_user(sg_io64.timeout, &sg_io32->timeout);
191         err |= __get_user(sg_io64.flags, &sg_io32->flags);
192         err |= __get_user(sg_io64.pack_id, &sg_io32->pack_id);
193
194         sg_io64.dxferp = NULL;
195         sg_io64.cmdp = NULL;
196         sg_io64.sbp = NULL;
197
198         err |= __get_user(cmdp32, &sg_io32->cmdp);
199         sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL);
200         if (!sg_io64.cmdp) {
201                 err = -ENOMEM;
202                 goto out;
203         }
204         if (copy_from_user(sg_io64.cmdp,
205                            (void *) P(cmdp32),
206                            sg_io64.cmd_len)) {
207                 err = -EFAULT;
208                 goto out;
209         }
210
211         err |= __get_user(sbp32, &sg_io32->sbp);
212         sg_io64.sbp = kmalloc(sg_io64.mx_sb_len, GFP_KERNEL);
213         if (!sg_io64.sbp) {
214                 err = -ENOMEM;
215                 goto out;
216         }
217         if (copy_from_user(sg_io64.sbp,
218                            (void *) P(sbp32),
219                            sg_io64.mx_sb_len)) {
220                 err = -EFAULT;
221                 goto out;
222         }
223
224         err |= __get_user(dxferp32, &sg_io32->dxferp);
225         if (sg_io64.iovec_count) {
226                 int ret;
227
228                 if ((ret = alloc_sg_iovec(&sg_io64, dxferp32))) {
229                         err = ret;
230                         goto out;
231                 }
232         } else {
233                 sg_io64.dxferp = kmalloc(sg_io64.dxfer_len, GFP_KERNEL);
234                 if (!sg_io64.dxferp) {
235                         err = -ENOMEM;
236                         goto out;
237                 }
238                 if (copy_from_user(sg_io64.dxferp,
239                                    (void *) P(dxferp32),
240                                    sg_io64.dxfer_len)) {
241                         err = -EFAULT;
242                         goto out;
243                 }
244         }
245
246         /* Unused internally, do not even bother to copy it over. */
247         sg_io64.usr_ptr = NULL;
248
249         if (err)
250                 return -EFAULT;
251
252         old_fs = get_fs();
253         set_fs (KERNEL_DS);
254         err = sys_ioctl (fd, cmd, (unsigned long) &sg_io64);
255         set_fs (old_fs);
256
257         if (err < 0)
258                 goto out;
259
260         err = __put_user(sg_io64.pack_id, &sg_io32->pack_id);
261         err |= __put_user(sg_io64.status, &sg_io32->status);
262         err |= __put_user(sg_io64.masked_status, &sg_io32->masked_status);
263         err |= __put_user(sg_io64.msg_status, &sg_io32->msg_status);
264         err |= __put_user(sg_io64.sb_len_wr, &sg_io32->sb_len_wr);
265         err |= __put_user(sg_io64.host_status, &sg_io32->host_status);
266         err |= __put_user(sg_io64.driver_status, &sg_io32->driver_status);
267         err |= __put_user(sg_io64.resid, &sg_io32->resid);
268         err |= __put_user(sg_io64.duration, &sg_io32->duration);
269         err |= __put_user(sg_io64.info, &sg_io32->info);
270         err |= copy_to_user((void *)P(sbp32), sg_io64.sbp, sg_io64.mx_sb_len);
271         if (sg_io64.dxferp) {
272                 if (sg_io64.iovec_count)
273                         err |= copy_back_sg_iovec(&sg_io64, dxferp32);
274                 else
275                         err |= copy_to_user((void *)P(dxferp32),
276                                             sg_io64.dxferp,
277                                             sg_io64.dxfer_len);
278         }
279         if (err)
280                 err = -EFAULT;
281
282 out:
283         if (sg_io64.cmdp)
284                 kfree(sg_io64.cmdp);
285         if (sg_io64.sbp)
286                 kfree(sg_io64.sbp);
287         if (sg_io64.dxferp) {
288                 if (sg_io64.iovec_count) {
289                         free_sg_iovec(&sg_io64);
290                 } else {
291                         kfree(sg_io64.dxferp);
292                 }
293         }
294         return err;
295 }