File: /usr/src/linux/arch/s390x/kernel/ioctl32.c

1     /*
2      * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
3      *
4      *  S390 version
5      *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6      *    Author(s): Gerhard Tonn (ton@de.ibm.com)
7      *
8      * Heavily inspired by the 32-bit Sparc compat code which is  
9      * Copyright (C) 2000 Silicon Graphics, Inc.
10      * Written by Ulf Carlsson (ulfc@engr.sgi.com) 
11      *
12      */
13     
14     #include <linux/types.h>
15     #include <linux/kernel.h>
16     #include <linux/fs.h>
17     #include <linux/sched.h>
18     #include <linux/mm.h>
19     #include <linux/init.h>
20     #include <linux/file.h>
21     #include <linux/vt.h>
22     #include <linux/kd.h>
23     #include <linux/netdevice.h>
24     #include <linux/route.h>
25     #include <linux/ext2_fs.h>
26     #include <linux/hdreg.h>
27     #include <asm/types.h>
28     #include <asm/uaccess.h>
29     #include <asm/dasd.h>
30     
31     #include "linux32.h"
32     
33     long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
34     
35     struct hd_geometry32 {
36     	unsigned char	heads;
37     	unsigned char	sectors;
38     	unsigned short	cylinders;
39     	__u32		start;
40     };  
41     
42     static inline int hd_geometry_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
43     {
44     	struct hd_geometry32 *hg32 = (struct hd_geometry32 *) A(arg);
45     	struct hd_geometry hg;
46     	int ret;
47     	mm_segment_t old_fs = get_fs();
48     	
49     	set_fs (KERNEL_DS);
50     	ret = sys_ioctl (fd, cmd, (long)&hg);
51     	set_fs (old_fs);
52     
53     	if (ret)
54     		return ret;
55     
56     	ret = put_user (hg.heads, &(hg32->heads));
57     	ret |= __put_user (hg.sectors, &(hg32->sectors));
58     	ret |= __put_user (hg.cylinders, &(hg32->cylinders));
59     	ret |= __put_user (hg.start, &(hg32->start));
60     
61     	return ret;
62     }
63     
64     struct timeval32 {
65     	int tv_sec;
66     	int tv_usec;
67     };
68     
69     #define EXT2_IOC32_GETFLAGS               _IOR('f', 1, int)
70     #define EXT2_IOC32_SETFLAGS               _IOW('f', 2, int)
71     #define EXT2_IOC32_GETVERSION             _IOR('v', 1, int)
72     #define EXT2_IOC32_SETVERSION             _IOW('v', 2, int)
73     
74     struct ifmap32 {
75     	unsigned int mem_start;
76     	unsigned int mem_end;
77     	unsigned short base_addr;
78     	unsigned char irq;
79     	unsigned char dma;
80     	unsigned char port;
81     };
82     
83     struct ifreq32 {
84     #define IFHWADDRLEN     6
85     #define IFNAMSIZ        16
86             union {
87                     char    ifrn_name[IFNAMSIZ];	/* if name, e.g. "en0" */
88             } ifr_ifrn;
89             union {
90                     struct  sockaddr ifru_addr;
91                     struct  sockaddr ifru_dstaddr;
92                     struct  sockaddr ifru_broadaddr;
93                     struct  sockaddr ifru_netmask;
94                     struct  sockaddr ifru_hwaddr;
95                     short   ifru_flags;
96                     int     ifru_ivalue;
97                     int     ifru_mtu;
98                     struct  ifmap32 ifru_map;
99                     char    ifru_slave[IFNAMSIZ];   /* Just fits the size */
100     		char	ifru_newname[IFNAMSIZ];
101                     __u32	ifru_data;
102             } ifr_ifru;
103     };
104     
105     struct ifconf32 {
106             int     ifc_len;                        /* size of buffer       */
107             __u32	ifcbuf;
108     };
109     
110     static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg)
111     {
112     	struct ireq32 *uir32 = (struct ireq32 *) A(arg);
113     	struct net_device *dev;
114     	struct ifreq32 ifr32;
115     
116     	if (copy_from_user(&ifr32, uir32, sizeof(struct ifreq32)))
117     		return -EFAULT;
118     
119     	read_lock(&dev_base_lock);
120     	dev = __dev_get_by_index(ifr32.ifr_ifindex);
121     	if (!dev) {
122     		read_unlock(&dev_base_lock);
123     		return -ENODEV;
124     	}
125     
126     	strcpy(ifr32.ifr_name, dev->name);
127     	read_unlock(&dev_base_lock);
128     
129     	if (copy_to_user(uir32, &ifr32, sizeof(struct ifreq32)))
130     	    return -EFAULT;
131     
132     	return 0;
133     }
134     
135     static inline int dev_ifconf(unsigned int fd, unsigned int cmd,
136     			     unsigned long arg)
137     {
138     	struct ioconf32 *uifc32 = (struct ioconf32 *) A(arg);
139     	struct ifconf32 ifc32;
140     	struct ifconf ifc;
141     	struct ifreq32 *ifr32;
142     	struct ifreq *ifr;
143     	mm_segment_t old_fs;
144     	int len;
145     	int err;
146     
147     	if (copy_from_user(&ifc32, uifc32, sizeof(struct ifconf32)))
148     		return -EFAULT;
149     
150     	if(ifc32.ifcbuf == 0) {
151     		ifc32.ifc_len = 0;
152     		ifc.ifc_len = 0;
153     		ifc.ifc_buf = NULL;
154     	} else {
155     		ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32))) *
156     			sizeof (struct ifreq);
157     		ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL);
158     		if (!ifc.ifc_buf)
159     			return -ENOMEM;
160     	}
161     	ifr = ifc.ifc_req;
162     	ifr32 = (struct ifreq32 *) A(ifc32.ifcbuf);
163     	len = ifc32.ifc_len / sizeof (struct ifreq32);
164     	while (len--) {
165     		if (copy_from_user(ifr++, ifr32++, sizeof (struct ifreq32))) {
166     			err = -EFAULT;
167     			goto out;
168     		}
169     	}
170     
171     	old_fs = get_fs();
172     	set_fs (KERNEL_DS);
173     	err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc);	
174     	set_fs (old_fs);
175     	if (err)
176     		goto out;
177     
178     	ifr = ifc.ifc_req;
179     	ifr32 = (struct ifreq32 *) A(ifc32.ifcbuf);
180     	len = ifc.ifc_len / sizeof (struct ifreq);
181     	ifc32.ifc_len = len * sizeof (struct ifreq32);
182     
183     	while (len--) {
184     		if (copy_to_user(ifr32++, ifr++, sizeof (struct ifreq32))) {
185     			err = -EFAULT;
186     			goto out;
187     		}
188     	}
189     
190     	if (copy_to_user(uifc32, &ifc32, sizeof(struct ifconf32))) {
191     		err = -EFAULT;
192     		goto out;
193     	}
194     out:
195     	if(ifc.ifc_buf != NULL)
196     		kfree (ifc.ifc_buf);
197     	return err;
198     }
199     
200     static inline int dev_ifsioc(unsigned int fd, unsigned int cmd,
201     			     unsigned long arg)
202     {
203     	struct ifreq32 *uifr = (struct ifreq32 *) A(arg);
204     	struct ifreq ifr;
205     	mm_segment_t old_fs;
206     	int err;
207     	
208     	switch (cmd) {
209     	case SIOCSIFMAP:
210     		err = copy_from_user(&ifr, uifr, sizeof(ifr.ifr_name));
211     		err |= __get_user(ifr.ifr_map.mem_start, &(uifr->ifr_ifru.ifru_map.mem_start));
212     		err |= __get_user(ifr.ifr_map.mem_end, &(uifr->ifr_ifru.ifru_map.mem_end));
213     		err |= __get_user(ifr.ifr_map.base_addr, &(uifr->ifr_ifru.ifru_map.base_addr));
214     		err |= __get_user(ifr.ifr_map.irq, &(uifr->ifr_ifru.ifru_map.irq));
215     		err |= __get_user(ifr.ifr_map.dma, &(uifr->ifr_ifru.ifru_map.dma));
216     		err |= __get_user(ifr.ifr_map.port, &(uifr->ifr_ifru.ifru_map.port));
217     		if (err)
218     			return -EFAULT;
219     		break;
220     	default:
221     		if (copy_from_user(&ifr, uifr, sizeof(struct ifreq32)))
222     			return -EFAULT;
223     		break;
224     	}
225     	old_fs = get_fs();
226     	set_fs (KERNEL_DS);
227     	err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
228     	set_fs (old_fs);
229     	if (!err) {
230     		switch (cmd) {
231     		case SIOCGIFFLAGS:
232     		case SIOCGIFMETRIC:
233     		case SIOCGIFMTU:
234     		case SIOCGIFMEM:
235     		case SIOCGIFHWADDR:
236     		case SIOCGIFINDEX:
237     		case SIOCGIFADDR:
238     		case SIOCGIFBRDADDR:
239     		case SIOCGIFDSTADDR:
240     		case SIOCGIFNETMASK:
241     		case SIOCGIFTXQLEN:
242     			if (copy_to_user(uifr, &ifr, sizeof(struct ifreq32)))
243     				return -EFAULT;
244     			break;
245     		case SIOCGIFMAP:
246     			err = copy_to_user(uifr, &ifr, sizeof(ifr.ifr_name));
247     			err |= __put_user(ifr.ifr_map.mem_start, &(uifr->ifr_ifru.ifru_map.mem_start));
248     			err |= __put_user(ifr.ifr_map.mem_end, &(uifr->ifr_ifru.ifru_map.mem_end));
249     			err |= __put_user(ifr.ifr_map.base_addr, &(uifr->ifr_ifru.ifru_map.base_addr));
250     			err |= __put_user(ifr.ifr_map.irq, &(uifr->ifr_ifru.ifru_map.irq));
251     			err |= __put_user(ifr.ifr_map.dma, &(uifr->ifr_ifru.ifru_map.dma));
252     			err |= __put_user(ifr.ifr_map.port, &(uifr->ifr_ifru.ifru_map.port));
253     			if (err)
254     				err = -EFAULT;
255     			break;
256     		}
257     	}
258     	return err;
259     }
260     
261     struct rtentry32
262     {
263     	unsigned int	rt_pad1;
264     	struct sockaddr	rt_dst;		/* target address		*/
265     	struct sockaddr	rt_gateway;	/* gateway addr (RTF_GATEWAY)	*/
266     	struct sockaddr	rt_genmask;	/* target network mask (IP)	*/
267     	unsigned short	rt_flags;
268     	short		rt_pad2;
269     	unsigned int	rt_pad3;
270     	unsigned int	rt_pad4;
271     	short		rt_metric;	/* +1 for binary compatibility!	*/
272     	unsigned int	rt_dev;		/* forcing the device at add	*/
273     	unsigned int	rt_mtu;		/* per route MTU/Window 	*/
274     #ifndef __KERNEL__
275     #define rt_mss	rt_mtu			/* Compatibility :-(            */
276     #endif
277     	unsigned int	rt_window;	/* Window clamping 		*/
278     	unsigned short	rt_irtt;	/* Initial RTT			*/
279     };
280     
281     static inline int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
282     {
283     	struct rtentry32 *ur = (struct rtentry32 *) A(arg);
284     	struct rtentry r;
285     	char devname[16];
286     	u32 rtdev;
287     	int ret;
288     	mm_segment_t old_fs = get_fs();
289     	
290     	ret = copy_from_user (&r.rt_dst, &(ur->rt_dst), 3 * sizeof(struct sockaddr));
291     	ret |= __get_user (r.rt_flags, &(ur->rt_flags));
292     	ret |= __get_user (r.rt_metric, &(ur->rt_metric));
293     	ret |= __get_user (r.rt_mtu, &(ur->rt_mtu));
294     	ret |= __get_user (r.rt_window, &(ur->rt_window));
295     	ret |= __get_user (r.rt_irtt, &(ur->rt_irtt));
296     	ret |= __get_user (rtdev, &(ur->rt_dev));
297     	if (rtdev) {
298     		ret |= copy_from_user (devname, (char *) A(rtdev), 15);
299     		r.rt_dev = devname; devname[15] = 0;
300     	} else
301     		r.rt_dev = 0;
302     	if (ret)
303     		return -EFAULT;
304     	set_fs (KERNEL_DS);
305     	ret = sys_ioctl (fd, cmd, (long)&r);
306     	set_fs (old_fs);
307     	return ret;
308     }
309     
310     static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
311     {
312     	/* These are just misnamed, they actually get/put from/to user an int */
313     	switch (cmd) {
314     	case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break;
315     	case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break;
316     	case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break;
317     	case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break;
318     	}
319     	return sys_ioctl(fd, cmd, arg);
320     }
321     
322     static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg)
323     {
324     	mm_segment_t old_fs = get_fs();
325     	int err;
326     	unsigned long val;
327     	
328     	set_fs (KERNEL_DS);
329     	err = sys_ioctl(fd, cmd, (unsigned long)&val);
330     	set_fs (old_fs);
331     	if (!err && put_user((unsigned int) val, (u32 *)arg))
332     		return -EFAULT;
333     	return err;
334     }
335     
336     struct ioctl32_handler {
337     	unsigned int cmd;
338     	int (*function)(unsigned int, unsigned int, unsigned long);
339     };
340     
341     struct ioctl32_list {
342     	struct ioctl32_handler handler;
343     	struct ioctl32_list *next;
344     };
345     
346     #define IOCTL32_DEFAULT(cmd)		{ { cmd, (void *) sys_ioctl }, 0 }
347     #define IOCTL32_HANDLER(cmd, handler)	{ { cmd, (void *) handler }, 0 }
348     
349     static struct ioctl32_list ioctl32_handler_table[] = {
350     	IOCTL32_DEFAULT(FIBMAP),
351     	IOCTL32_DEFAULT(FIGETBSZ),
352     
353     	IOCTL32_DEFAULT(DASDAPIVER),
354     	IOCTL32_DEFAULT(BIODASDDISABLE),
355     	IOCTL32_DEFAULT(BIODASDENABLE),
356     	IOCTL32_DEFAULT(BIODASDRSRV),
357     	IOCTL32_DEFAULT(BIODASDRLSE),
358     	IOCTL32_DEFAULT(BIODASDSLCK),
359     	IOCTL32_DEFAULT(BIODASDINFO),
360     	IOCTL32_DEFAULT(BIODASDFMT),
361     
362     	IOCTL32_DEFAULT(BLKRRPART),
363     
364     	IOCTL32_HANDLER(HDIO_GETGEO, hd_geometry_ioctl),
365     
366     	IOCTL32_DEFAULT(TCGETA),
367     	IOCTL32_DEFAULT(TCSETA),
368     	IOCTL32_DEFAULT(TCSETAW),
369     	IOCTL32_DEFAULT(TCSETAF),
370     	IOCTL32_DEFAULT(TCSBRK),
371     	IOCTL32_DEFAULT(TCXONC),
372     	IOCTL32_DEFAULT(TCFLSH),
373     	IOCTL32_DEFAULT(TCGETS),
374     	IOCTL32_DEFAULT(TCSETS),
375     	IOCTL32_DEFAULT(TCSETSW),
376     	IOCTL32_DEFAULT(TCSETSF),
377     	IOCTL32_DEFAULT(TIOCLINUX),
378     
379     	IOCTL32_DEFAULT(TIOCGETD),
380     	IOCTL32_DEFAULT(TIOCSETD),
381     	IOCTL32_DEFAULT(TIOCEXCL),
382     	IOCTL32_DEFAULT(TIOCNXCL),
383     	IOCTL32_DEFAULT(TIOCCONS),
384     	IOCTL32_DEFAULT(TIOCGSOFTCAR),
385     	IOCTL32_DEFAULT(TIOCSSOFTCAR),
386     	IOCTL32_DEFAULT(TIOCSWINSZ),
387     	IOCTL32_DEFAULT(TIOCGWINSZ),
388     	IOCTL32_DEFAULT(TIOCMGET),
389     	IOCTL32_DEFAULT(TIOCMBIC),
390     	IOCTL32_DEFAULT(TIOCMBIS),
391     	IOCTL32_DEFAULT(TIOCMSET),
392     	IOCTL32_DEFAULT(TIOCPKT),
393     	IOCTL32_DEFAULT(TIOCNOTTY),
394     	IOCTL32_DEFAULT(TIOCSTI),
395     	IOCTL32_DEFAULT(TIOCOUTQ),
396     	IOCTL32_DEFAULT(TIOCSPGRP),
397     	IOCTL32_DEFAULT(TIOCGPGRP),
398     	IOCTL32_DEFAULT(TIOCSCTTY),
399     	IOCTL32_DEFAULT(TIOCGPTN),
400     	IOCTL32_DEFAULT(TIOCSPTLCK),
401     	IOCTL32_DEFAULT(TIOCGSERIAL),
402     	IOCTL32_DEFAULT(TIOCSSERIAL),
403     	IOCTL32_DEFAULT(TIOCSERGETLSR),
404     
405     	IOCTL32_DEFAULT(FIOCLEX),
406     	IOCTL32_DEFAULT(FIONCLEX),
407     	IOCTL32_DEFAULT(FIOASYNC),
408     	IOCTL32_DEFAULT(FIONBIO),
409     	IOCTL32_DEFAULT(FIONREAD),
410     
411     	IOCTL32_DEFAULT(PIO_FONT),
412     	IOCTL32_DEFAULT(GIO_FONT),
413     	IOCTL32_DEFAULT(KDSIGACCEPT),
414     	IOCTL32_DEFAULT(KDGETKEYCODE),
415     	IOCTL32_DEFAULT(KDSETKEYCODE),
416     	IOCTL32_DEFAULT(KIOCSOUND),
417     	IOCTL32_DEFAULT(KDMKTONE),
418     	IOCTL32_DEFAULT(KDGKBTYPE),
419     	IOCTL32_DEFAULT(KDSETMODE),
420     	IOCTL32_DEFAULT(KDGETMODE),
421     	IOCTL32_DEFAULT(KDSKBMODE),
422     	IOCTL32_DEFAULT(KDGKBMODE),
423     	IOCTL32_DEFAULT(KDSKBMETA),
424     	IOCTL32_DEFAULT(KDGKBMETA),
425     	IOCTL32_DEFAULT(KDGKBENT),
426     	IOCTL32_DEFAULT(KDSKBENT),
427     	IOCTL32_DEFAULT(KDGKBSENT),
428     	IOCTL32_DEFAULT(KDSKBSENT),
429     	IOCTL32_DEFAULT(KDGKBDIACR),
430     	IOCTL32_DEFAULT(KDSKBDIACR),
431     	IOCTL32_DEFAULT(KDGKBLED),
432     	IOCTL32_DEFAULT(KDSKBLED),
433     	IOCTL32_DEFAULT(KDGETLED),
434     	IOCTL32_DEFAULT(KDSETLED),
435     	IOCTL32_DEFAULT(GIO_SCRNMAP),
436     	IOCTL32_DEFAULT(PIO_SCRNMAP),
437     	IOCTL32_DEFAULT(GIO_UNISCRNMAP),
438     	IOCTL32_DEFAULT(PIO_UNISCRNMAP),
439     	IOCTL32_DEFAULT(PIO_FONTRESET),
440     	IOCTL32_DEFAULT(PIO_UNIMAPCLR),
441     
442     	IOCTL32_DEFAULT(VT_SETMODE),
443     	IOCTL32_DEFAULT(VT_GETMODE),
444     	IOCTL32_DEFAULT(VT_GETSTATE),
445     	IOCTL32_DEFAULT(VT_OPENQRY),
446     	IOCTL32_DEFAULT(VT_ACTIVATE),
447     	IOCTL32_DEFAULT(VT_WAITACTIVE),
448     	IOCTL32_DEFAULT(VT_RELDISP),
449     	IOCTL32_DEFAULT(VT_DISALLOCATE),
450     	IOCTL32_DEFAULT(VT_RESIZE),
451     	IOCTL32_DEFAULT(VT_RESIZEX),
452     	IOCTL32_DEFAULT(VT_LOCKSWITCH),
453     	IOCTL32_DEFAULT(VT_UNLOCKSWITCH),
454     
455     	IOCTL32_HANDLER(SIOCGIFNAME, dev_ifname32),
456     	IOCTL32_HANDLER(SIOCGIFCONF, dev_ifconf),
457     	IOCTL32_HANDLER(SIOCGIFFLAGS, dev_ifsioc),
458     	IOCTL32_HANDLER(SIOCSIFFLAGS, dev_ifsioc),
459     	IOCTL32_HANDLER(SIOCGIFMETRIC, dev_ifsioc),
460     	IOCTL32_HANDLER(SIOCSIFMETRIC, dev_ifsioc),
461     	IOCTL32_HANDLER(SIOCGIFMTU, dev_ifsioc),
462     	IOCTL32_HANDLER(SIOCSIFMTU, dev_ifsioc),
463     	IOCTL32_HANDLER(SIOCGIFMEM, dev_ifsioc),
464     	IOCTL32_HANDLER(SIOCSIFMEM, dev_ifsioc),
465     	IOCTL32_HANDLER(SIOCGIFHWADDR, dev_ifsioc),
466     	IOCTL32_HANDLER(SIOCSIFHWADDR, dev_ifsioc),
467     	IOCTL32_HANDLER(SIOCADDMULTI, dev_ifsioc),
468     	IOCTL32_HANDLER(SIOCDELMULTI, dev_ifsioc),
469     	IOCTL32_HANDLER(SIOCGIFINDEX, dev_ifsioc),
470     	IOCTL32_HANDLER(SIOCGIFMAP, dev_ifsioc),
471     	IOCTL32_HANDLER(SIOCSIFMAP, dev_ifsioc),
472     	IOCTL32_HANDLER(SIOCGIFADDR, dev_ifsioc),
473     	IOCTL32_HANDLER(SIOCSIFADDR, dev_ifsioc),
474     	IOCTL32_HANDLER(SIOCGIFBRDADDR, dev_ifsioc),
475     	IOCTL32_HANDLER(SIOCSIFBRDADDR, dev_ifsioc),
476     	IOCTL32_HANDLER(SIOCGIFDSTADDR, dev_ifsioc),
477     	IOCTL32_HANDLER(SIOCSIFDSTADDR, dev_ifsioc),
478     	IOCTL32_HANDLER(SIOCGIFNETMASK, dev_ifsioc),
479     	IOCTL32_HANDLER(SIOCSIFNETMASK, dev_ifsioc),
480     	IOCTL32_HANDLER(SIOCSIFPFLAGS, dev_ifsioc),
481     	IOCTL32_HANDLER(SIOCGIFPFLAGS, dev_ifsioc),
482     	IOCTL32_HANDLER(SIOCGIFTXQLEN, dev_ifsioc),
483     	IOCTL32_HANDLER(SIOCSIFTXQLEN, dev_ifsioc),
484     	IOCTL32_HANDLER(SIOCADDRT, routing_ioctl),
485     	IOCTL32_HANDLER(SIOCDELRT, routing_ioctl),
486     
487     	IOCTL32_HANDLER(EXT2_IOC32_GETFLAGS, do_ext2_ioctl),
488     	IOCTL32_HANDLER(EXT2_IOC32_SETFLAGS, do_ext2_ioctl),
489     	IOCTL32_HANDLER(EXT2_IOC32_GETVERSION, do_ext2_ioctl),
490     	IOCTL32_HANDLER(EXT2_IOC32_SETVERSION, do_ext2_ioctl),
491     
492     	IOCTL32_HANDLER(BLKGETSIZE, w_long)
493     
494     };
495     
496     #define NR_IOCTL32_HANDLERS	(sizeof(ioctl32_handler_table) /	\
497     				 sizeof(ioctl32_handler_table[0]))
498     
499     static struct ioctl32_list *ioctl32_hash_table[1024];
500     
501     static inline int ioctl32_hash(unsigned int cmd)
502     {
503     	return ((cmd >> 6) ^ (cmd >> 4) ^ cmd) & 0x3ff;
504     }
505     
506     int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
507     {
508     	int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
509     	struct file *filp;
510     	struct ioctl32_list *l;
511     	int error;
512     
513     	l = ioctl32_hash_table[ioctl32_hash(cmd)];
514     
515     	error = -EBADF;
516     
517     	filp = fget(fd);
518     	if (!filp)
519     		return error;
520     
521     	if (!filp->f_op || !filp->f_op->ioctl) {
522     		error = sys_ioctl (fd, cmd, arg);
523     		goto out;
524     	}
525     
526     	while (l && l->handler.cmd != cmd)
527     		l = l->next;
528     
529     	if (l) {
530     		handler = (void *)l->handler.function;
531     		error = handler(fd, cmd, arg, filp);
532     	} else {
533     		error = -EINVAL;
534     		printk("unknown ioctl: %08x\n", cmd);
535     	}
536     out:
537     	fput(filp);
538     	return error;
539     }
540     
541     static void ioctl32_insert(struct ioctl32_list *entry)
542     {
543     	int hash = ioctl32_hash(entry->handler.cmd);
544     	if (!ioctl32_hash_table[hash])
545     		ioctl32_hash_table[hash] = entry;
546     	else {
547     		struct ioctl32_list *l;
548     		l = ioctl32_hash_table[hash];
549     		while (l->next)
550     			l = l->next;
551     		l->next = entry;
552     		entry->next = 0;
553     	}
554     }
555     
556     static int __init init_ioctl32(void)
557     {
558     	int i;
559     	for (i = 0; i < NR_IOCTL32_HANDLERS; i++)
560     		ioctl32_insert(&ioctl32_handler_table[i]);
561     	return 0;
562     }
563     
564     __initcall(init_ioctl32);
565