static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	struct hiddev_list *list = file->private_data;	struct hiddev *hiddev = list->hiddev;	struct hid_device *hid = hiddev->hid;	struct usb_device *dev = hid->dev;	struct hiddev_collection_info cinfo;	struct hiddev_report_info rinfo;	struct hiddev_field_info finfo;	struct hiddev_usage_ref_multi *uref_multi=NULL;	struct hiddev_usage_ref *uref;	struct hiddev_devinfo dinfo;	struct hid_report *report;	struct hid_field *field;	void __user *user_arg = (void __user *)arg;	int i;	if (!hiddev->exist)		return -EIO;	switch (cmd) {	case HIDIOCGVERSION:		return put_user(HID_VERSION, (int __user *)arg);	case HIDIOCAPPLICATION:		if (arg < 0 || arg >= hid->maxapplication)			return -EINVAL;		for (i = 0; i < hid->maxcollection; i++)			if (hid->collection[i].type == 			    HID_COLLECTION_APPLICATION && arg-- == 0)				break;				if (i == hid->maxcollection)			return -EINVAL;		return hid->collection[i].usage;	case HIDIOCGDEVINFO:		dinfo.bustype = BUS_USB;		dinfo.busnum = dev->bus->busnum;		dinfo.devnum = dev->devnum;		dinfo.ifnum = hid->ifnum;		dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);		dinfo.product = le16_to_cpu(dev->descriptor.idProduct);		dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);		dinfo.num_applications = hid->maxapplication;		if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))			return -EFAULT;		return 0;	case HIDIOCGFLAG:		if (put_user(list->flags, (int __user *)arg))			return -EFAULT;		return 0;	case HIDIOCSFLAG:		{			int newflags;			if (get_user(newflags, (int __user *)arg))				return -EFAULT;			if ((newflags & ~HIDDEV_FLAGS) != 0 ||			    ((newflags & HIDDEV_FLAG_REPORT) != 0 &&			     (newflags & HIDDEV_FLAG_UREF) == 0))				return -EINVAL;			list->flags = newflags;			return 0;		}	case HIDIOCGSTRING:		{			int idx, len;			char *buf;			if (get_user(idx, (int __user *)arg))				return -EFAULT;			if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)				return -ENOMEM;			if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {				kfree(buf);				return -EINVAL;			}			if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {				kfree(buf);				return -EFAULT;			}			kfree(buf);			return len;		}	case HIDIOCINITREPORT:		hid_init_reports(hid);		return 0;	case HIDIOCGREPORT:		if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))			return -EFAULT;		if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT)			return -EINVAL;		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)			return -EINVAL;		hid_submit_report(hid, report, USB_DIR_IN);		hid_wait_io(hid);		return 0;	case HIDIOCSREPORT:		if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))			return -EFAULT;		if (rinfo.report_type == HID_REPORT_TYPE_INPUT)			return -EINVAL;		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)			return -EINVAL;		hid_submit_report(hid, report, USB_DIR_OUT);		return 0;	case HIDIOCGREPORTINFO:		if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))			return -EFAULT;		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)			return -EINVAL;		rinfo.num_fields = report->maxfield;		if (copy_to_user(user_arg, &rinfo, sizeof(rinfo)))			return -EFAULT;		return 0;	case HIDIOCGFIELDINFO:		if (copy_from_user(&finfo, user_arg, sizeof(finfo)))			return -EFAULT;		rinfo.report_type = finfo.report_type;		rinfo.report_id = finfo.report_id;		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)			return -EINVAL;		if (finfo.field_index >= report->maxfield)			return -EINVAL;		field = report->field[finfo.field_index];		memset(&finfo, 0, sizeof(finfo));		finfo.report_type = rinfo.report_type;		finfo.report_id = rinfo.report_id;		finfo.field_index = field->report_count - 1;		finfo.maxusage = field->maxusage;		finfo.flags = field->flags;		finfo.physical = field->physical;		finfo.logical = field->logical;		finfo.application = field->application;		finfo.logical_minimum = field->logical_minimum;		finfo.logical_maximum = field->logical_maximum;		finfo.physical_minimum = field->physical_minimum;		finfo.physical_maximum = field->physical_maximum;		finfo.unit_exponent = field->unit_exponent;		finfo.unit = field->unit;		if (copy_to_user(user_arg, &finfo, sizeof(finfo)))			return -EFAULT;		return 0;	case HIDIOCGUCODE:		uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);		if (!uref_multi)			return -ENOMEM;		uref = &uref_multi->uref;		if (copy_from_user(uref, user_arg, sizeof(*uref))) 			goto fault;		rinfo.report_type = uref->report_type;		rinfo.report_id = uref->report_id;		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)			goto inval;		if (uref->field_index >= report->maxfield)			goto inval;		field = report->field[uref->field_index];		if (uref->usage_index >= field->maxusage)			goto inval;		uref->usage_code = field->usage[uref->usage_index].hid;		if (copy_to_user(user_arg, uref, sizeof(*uref)))			goto fault;		kfree(uref_multi);		return 0;	case HIDIOCGUSAGE:	case HIDIOCSUSAGE:	case HIDIOCGUSAGES:	case HIDIOCSUSAGES:	case HIDIOCGCOLLECTIONINDEX:		uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);		if (!uref_multi)			return -ENOMEM;		uref = &uref_multi->uref;		if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {			if (copy_from_user(uref_multi, user_arg, 					   sizeof(*uref_multi)))				goto fault;		} else {			if (copy_from_user(uref, user_arg, sizeof(*uref)))				goto fault;		}		if (cmd != HIDIOCGUSAGE && 		    cmd != HIDIOCGUSAGES &&		    uref->report_type == HID_REPORT_TYPE_INPUT)			goto inval;		if (uref->report_id == HID_REPORT_ID_UNKNOWN) {			field = hiddev_lookup_usage(hid, uref);			if (field == NULL)				goto inval;		} else {			rinfo.report_type = uref->report_type;			rinfo.report_id = uref->report_id;			if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)				goto inval;			if (uref->field_index >= report->maxfield)				goto inval;			field = report->field[uref->field_index];			if (cmd == HIDIOCGCOLLECTIONINDEX) {				if (uref->usage_index >= field->maxusage)					goto inval;			} else if (uref->usage_index >= field->report_count)				goto inval;			else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&				 (uref_multi->num_values > HID_MAX_MULTI_USAGES ||				  uref->usage_index + uref_multi->num_values >= field->report_count))				goto inval;			}		switch (cmd) {			case HIDIOCGUSAGE:				uref->value = field->value[uref->usage_index];				if (copy_to_user(user_arg, uref, sizeof(*uref)))					goto fault;				goto goodreturn;			case HIDIOCSUSAGE:				field->value[uref->usage_index] = uref->value;				goto goodreturn;			case HIDIOCGCOLLECTIONINDEX:				kfree(uref_multi);				return field->usage[uref->usage_index].collection_index;			case HIDIOCGUSAGES:				for (i = 0; i < uref_multi->num_values; i++)					uref_multi->values[i] = 					    field->value[uref->usage_index + i];				if (copy_to_user(user_arg, uref_multi, 						 sizeof(*uref_multi)))					goto fault;				goto goodreturn;			case HIDIOCSUSAGES:				for (i = 0; i < uref_multi->num_values; i++)					field->value[uref->usage_index + i] = 				  	    uref_multi->values[i];				goto goodreturn;		}goodreturn:		kfree(uref_multi);		return 0;fault:		kfree(uref_multi);		return -EFAULT;inval:				kfree(uref_multi);		return -EINVAL;	case HIDIOCGCOLLECTIONINFO:		if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))			return -EFAULT;		if (cinfo.index >= hid->maxcollection)			return -EINVAL;		cinfo.type = hid->collection[cinfo.index].type;		cinfo.usage = hid->collection[cinfo.index].usage;		cinfo.level = hid->collection[cinfo.index].level;		if (copy_to_user(user_arg, &cinfo, sizeof(cinfo)))			return -EFAULT;		return 0;	default:		if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)			return -EINVAL;		if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) {			int len;			if (!hid->name)				return 0;			len = strlen(hid->name) + 1;			if (len > _IOC_SIZE(cmd))				 len = _IOC_SIZE(cmd);			return copy_to_user(user_arg, hid->name, len) ?				-EFAULT : len;		}		if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {			int len;			if (!hid->phys)				return 0;			len = strlen(hid->phys) + 1;			if (len > _IOC_SIZE(cmd))				len = _IOC_SIZE(cmd);			return copy_to_user(user_arg, hid->phys, len) ?				-EFAULT : len;		}	}	return -EINVAL;}
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/05f091ab4c8c1f12f8dd38ee789489904fea327d/hiddev.c/clean/drivers/usb/input/hiddev.c