ioctl32.c

来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 2,297 行 · 第 1/5 页

C
2,297
字号
/* * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 2000 Silicon Graphics, Inc. * Written by Ulf Carlsson (ulfc@engr.sgi.com) * Copyright (C) 2000 Ralf Baechle * Copyright (C) 2002, 2003  Maciej W. Rozycki * * Mostly stolen from the sparc64 ioctl32 implementation. */#include <linux/config.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/sched.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/ioctl.h>#include <linux/if.h>#include <linux/slab.h>#include <linux/hdreg.h>#include <linux/raid/md_u.h>#include <linux/kd.h>#include <linux/route.h>#include <linux/vt.h>#include <linux/fs.h>#include <linux/ppp_defs.h>#include <linux/if_ppp.h>#include <linux/if_pppox.h>#include <linux/if_tun.h>#include <linux/mtio.h>#include <linux/cdrom.h>#include <linux/loop.h>#include <linux/auto_fs.h>#include <linux/auto_fs4.h>#include <linux/devfs_fs.h>#include <linux/tty.h>#include <linux/vt_kern.h>#include <linux/fb.h>#include <linux/ext2_fs.h>#include <linux/videodev.h>#include <linux/netdevice.h>#include <linux/raw.h>#include <linux/blkpg.h>#include <linux/blk.h>#include <linux/elevator.h>#include <linux/file.h>#include <linux/rtc.h>#include <linux/pci.h>#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)#include <linux/lvm.h>#endif /* LVM */#include <scsi/scsi.h>#undef __KERNEL__		/* This file was born to be ugly ...  */#include <scsi/scsi_ioctl.h>#define __KERNEL__#include <scsi/sg.h>#include <asm/types.h>#include <asm/uaccess.h>#include <linux/soundcard.h>#include <linux/mtd/mtd.h>#include <linux/serial.h>#ifdef CONFIG_SIBYTE_TBPROF#include <asm/sibyte/trace_prof.h>#endiflong sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg){	mm_segment_t old_fs = get_fs();	int err;	unsigned long val;	set_fs (KERNEL_DS);	err = sys_ioctl(fd, cmd, (unsigned long)&val);	set_fs (old_fs);	if (!err && put_user((unsigned int) val, (u32 *)arg))		return -EFAULT;	return err;}static int rw_long(unsigned int fd, unsigned int cmd, unsigned long arg){	mm_segment_t old_fs = get_fs();	int err;	unsigned long val;	if (get_user(val, (u32 *)arg))		return -EFAULT;	set_fs(KERNEL_DS);	err = sys_ioctl(fd, cmd, (unsigned long)&val);	set_fs (old_fs);	if (!err && put_user(val, (u32 *)arg))		return -EFAULT;	return err;}#define A(__x) ((unsigned long)(__x))#ifdef CONFIG_FBstruct fb_fix_screeninfo32 {	char id[16];			/* identification string eg "TT Builtin" */	__u32 smem_start;		/* Start of frame buffer mem */					/* (physical address) */	__u32 smem_len;			/* Length of frame buffer mem */	__u32 type;			/* see FB_TYPE_*		*/	__u32 type_aux;			/* Interleave for interleaved Planes */	__u32 visual;			/* see FB_VISUAL_*		*/ 	__u16 xpanstep;			/* zero if no hardware panning  */	__u16 ypanstep;			/* zero if no hardware panning  */	__u16 ywrapstep;		/* zero if no hardware ywrap    */	__u32 line_length;		/* length of a line in bytes    */	__u32 mmio_start;		/* Start of Memory Mapped I/O   */					/* (physical address) */	__u32 mmio_len;			/* Length of Memory Mapped I/O  */	__u32 accel;			/* Type of acceleration available */	__u16 reserved[3];		/* Reserved for future compatibility */};static int do_fbioget_fscreeninfo_ioctl(unsigned int fd, unsigned int cmd,					unsigned long arg){	mm_segment_t old_fs = get_fs();	struct fb_fix_screeninfo fix;	struct fb_fix_screeninfo32 *fix32 = (struct fb_fix_screeninfo32 *)arg;	int err;	set_fs(KERNEL_DS);	err = sys_ioctl(fd, cmd, (unsigned long)&fix);	set_fs(old_fs);	if (err == 0) {		err = __copy_to_user((char *)fix32->id, (char *)fix.id,				     sizeof(fix.id));		err |= __put_user((__u32)(unsigned long)fix.smem_start,				  &fix32->smem_start);		err |= __put_user(fix.smem_len, &fix32->smem_len);		err |= __put_user(fix.type, &fix32->type);		err |= __put_user(fix.type_aux, &fix32->type_aux);		err |= __put_user(fix.visual, &fix32->visual);		err |= __put_user(fix.xpanstep, &fix32->xpanstep);		err |= __put_user(fix.ypanstep, &fix32->ypanstep);		err |= __put_user(fix.ywrapstep, &fix32->ywrapstep);		err |= __put_user(fix.line_length, &fix32->line_length);		err |= __put_user((__u32)(unsigned long)fix.mmio_start,				  &fix32->mmio_start);		err |= __put_user(fix.mmio_len, &fix32->mmio_len);		err |= __put_user(fix.accel, &fix32->accel);		err |= __copy_to_user((char *)fix32->reserved,				      (char *)fix.reserved,				      sizeof(fix.reserved));		if (err)			err = -EFAULT;	}	return err;}struct fb_cmap32 {	__u32 start;			/* First entry  */	__u32 len;			/* Number of entries */	__u32 red;			/* Red values   */	__u32 green;	__u32 blue;	__u32 transp;			/* transparency, can be NULL */};static int do_fbiocmap_ioctl(unsigned int fd, unsigned int cmd,			     unsigned long arg){	mm_segment_t old_fs = get_fs();	u32 red = 0, green = 0, blue = 0, transp = 0;	struct fb_cmap cmap;	struct fb_cmap32 *cmap32 = (struct fb_cmap32 *)arg;	int err;	memset(&cmap, 0, sizeof(cmap));	err = __get_user(cmap.start, &cmap32->start);	err |= __get_user(cmap.len, &cmap32->len);	err |= __get_user(red, &cmap32->red);	err |= __get_user(green, &cmap32->green);	err |= __get_user(blue, &cmap32->blue);	err |= __get_user(transp, &cmap32->transp);	if (err)		return -EFAULT;	err = -ENOMEM;	cmap.red = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);	if (!cmap.red)		goto out;	cmap.green = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);	if (!cmap.green)		goto out;	cmap.blue = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);	if (!cmap.blue)		goto out;	if (transp) {		cmap.transp = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);		if (!cmap.transp)			goto out;	}				if (cmd == FBIOPUTCMAP) {		err = __copy_from_user(cmap.red, (char *)A(red),				       cmap.len * sizeof(__u16));		err |= __copy_from_user(cmap.green, (char *)A(green),					cmap.len * sizeof(__u16));		err |= __copy_from_user(cmap.blue, (char *)A(blue),					cmap.len * sizeof(__u16));		if (cmap.transp)			err |= __copy_from_user(cmap.transp, (char *)A(transp),						cmap.len * sizeof(__u16));		if (err) {			err = -EFAULT;			goto out;		}	}	set_fs(KERNEL_DS);	err = sys_ioctl(fd, cmd, (unsigned long)&cmap);	set_fs(old_fs);	if (err)		goto out;	if (cmd == FBIOGETCMAP) {		err = __copy_to_user((char *)A(red), cmap.red,				     cmap.len * sizeof(__u16));		err |= __copy_to_user((char *)A(green), cmap.blue,				      cmap.len * sizeof(__u16));		err |= __copy_to_user((char *)A(blue), cmap.blue,				      cmap.len * sizeof(__u16));		if (cmap.transp)			err |= __copy_to_user((char *)A(transp), cmap.transp,					      cmap.len * sizeof(__u16));		if (err) {			err = -EFAULT;			goto out;		}	}out:	if (cmap.red)		kfree(cmap.red);	if (cmap.green)		kfree(cmap.green);	if (cmap.blue)		kfree(cmap.blue);	if (cmap.transp)		kfree(cmap.transp);	return err;}#endif /* CONFIG_FB */struct timeval32 {	int tv_sec;	int tv_usec;};static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg){	struct timeval32 *up = (struct timeval32 *)arg;	struct timeval ktv;	mm_segment_t old_fs = get_fs();	int err;	set_fs(KERNEL_DS);	err = sys_ioctl(fd, cmd, (unsigned long)&ktv);	set_fs(old_fs);	if (!err) {		err = put_user(ktv.tv_sec, &up->tv_sec);		err |= __put_user(ktv.tv_usec, &up->tv_usec);	}	return err;}#define EXT2_IOC32_GETFLAGS               _IOR('f', 1, int)#define EXT2_IOC32_SETFLAGS               _IOW('f', 2, int)#define EXT2_IOC32_GETVERSION             _IOR('v', 1, int)#define EXT2_IOC32_SETVERSION             _IOW('v', 2, int)struct ifmap32 {	unsigned int mem_start;	unsigned int mem_end;	unsigned short base_addr;	unsigned char irq;	unsigned char dma;	unsigned char port;};struct ifreq32 {#define IFHWADDRLEN     6#define IFNAMSIZ        16        union {                char    ifrn_name[IFNAMSIZ];	/* if name, e.g. "en0" */        } ifr_ifrn;        union {                struct  sockaddr ifru_addr;                struct  sockaddr ifru_dstaddr;                struct  sockaddr ifru_broadaddr;                struct  sockaddr ifru_netmask;                struct  sockaddr ifru_hwaddr;                short   ifru_flags;                int     ifru_ivalue;                int     ifru_mtu;                struct  ifmap32 ifru_map;                char    ifru_slave[IFNAMSIZ];   /* Just fits the size */		char	ifru_newname[IFNAMSIZ];                __kernel_caddr_t32 ifru_data;        } ifr_ifru;};struct ifconf32 {        int     ifc_len;                        /* size of buffer       */        __kernel_caddr_t32  ifcbuf;};#ifdef CONFIG_NETstatic int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg){	struct ireq32 *uir32 = (struct ireq32 *)arg;	struct net_device *dev;	struct ifreq32 ifr32;	if (copy_from_user(&ifr32, uir32, sizeof(struct ifreq32)))		return -EFAULT;	read_lock(&dev_base_lock);	dev = __dev_get_by_index(ifr32.ifr_ifindex);	if (!dev) {		read_unlock(&dev_base_lock);		return -ENODEV;	}	strcpy(ifr32.ifr_name, dev->name);	read_unlock(&dev_base_lock);	if (copy_to_user(uir32, &ifr32, sizeof(struct ifreq32)))	    return -EFAULT;	return 0;}static inline int dev_ifconf(unsigned int fd, unsigned int cmd,			     unsigned long arg){	struct ioconf32 *uifc32 = (struct ioconf32 *)arg;	struct ifconf32 ifc32;	struct ifconf ifc;	struct ifreq32 *ifr32;	struct ifreq *ifr;	mm_segment_t old_fs;	unsigned int i, j;	int err;	if (copy_from_user(&ifc32, uifc32, sizeof(struct ifconf32)))		return -EFAULT;	if(ifc32.ifcbuf == 0) {		ifc32.ifc_len = 0;		ifc.ifc_len = 0;		ifc.ifc_buf = NULL;	} else {		ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32))) *			sizeof (struct ifreq);		ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL);		if (!ifc.ifc_buf)			return -ENOMEM;	}	ifr = ifc.ifc_req;	ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf);	for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) {		if (copy_from_user(ifr++, ifr32++, sizeof (struct ifreq32))) {			kfree (ifc.ifc_buf);			return -EFAULT;		}	}	old_fs = get_fs(); set_fs (KERNEL_DS);	err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc);	set_fs (old_fs);	if (err)		goto out;	ifr = ifc.ifc_req;	ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf);	for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len;	     i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) {		if (copy_to_user(ifr32++, ifr++, sizeof (struct ifreq32))) {			err = -EFAULT;			goto out;		}	}	if (ifc32.ifcbuf == 0) {		/* Translate from 64-bit structure multiple to		 * a 32-bit one.		 */		i = ifc.ifc_len;		i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32));		ifc32.ifc_len = i;	} else {		if (i <= ifc32.ifc_len)			ifc32.ifc_len = i;		else			ifc32.ifc_len = i - sizeof (struct ifreq32);	}	if (copy_to_user(uifc32, &ifc32, sizeof(struct ifconf32))) {		err = -EFAULT;		goto out;	}out:	if(ifc.ifc_buf != NULL)		kfree (ifc.ifc_buf);	return err;}static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg){	struct ifreq ifr;	mm_segment_t old_fs;	int err;		switch (cmd) {	case SIOCSIFMAP:		err = copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(ifr.ifr_name));		err |= __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start));		err |= __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end));		err |= __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr));		err |= __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq));		err |= __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma));		err |= __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port));		if (err)			return -EFAULT;		break;	default:		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))			return -EFAULT;		break;	}	old_fs = get_fs();	set_fs (KERNEL_DS);	err = sys_ioctl (fd, cmd, (unsigned long)&ifr);	set_fs (old_fs);	if (!err) {		switch (cmd) {		case SIOCGIFFLAGS:		case SIOCGIFMETRIC:		case SIOCGIFMTU:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?