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