⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hiddev.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
		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);		hid_wait_io(hid);		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;}static struct file_operations hiddev_fops = {	.owner =	THIS_MODULE,	.read =		hiddev_read,	.write =	hiddev_write,	.poll =		hiddev_poll,	.open =		hiddev_open,	.release =	hiddev_release,	.ioctl =	hiddev_ioctl,	.fasync =	hiddev_fasync,};static struct usb_class_driver hiddev_class = {	.name =		"hiddev%d",	.fops =		&hiddev_fops,	.minor_base =	HIDDEV_MINOR_BASE,};/* * This is where hid.c calls us to connect a hid device to the hiddev driver */int hiddev_connect(struct hid_device *hid){	struct hiddev *hiddev;	int i;	int retval;	for (i = 0; i < hid->maxcollection; i++)		if (hid->collection[i].type ==		    HID_COLLECTION_APPLICATION &&		    !IS_INPUT_APPLICATION(hid->collection[i].usage))			break;	if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)		return -1;	if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))		return -1;	memset(hiddev, 0, sizeof(struct hiddev));	retval = usb_register_dev(hid->intf, &hiddev_class);	if (retval) {		err("Not able to get a minor for this device.");		kfree(hiddev);		return -1;	}	init_waitqueue_head(&hiddev->wait);	hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;	hiddev->hid = hid;	hiddev->exist = 1;	hid->minor = hid->intf->minor;	hid->hiddev = hiddev;	return 0;}/* * This is where hid.c calls us to disconnect a hiddev device from the * corresponding hid device (usually because the usb device has disconnected) */static struct usb_class_driver hiddev_class;void hiddev_disconnect(struct hid_device *hid){	struct hiddev *hiddev = hid->hiddev;	hiddev->exist = 0;	hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;	usb_deregister_dev(hiddev->hid->intf, &hiddev_class);	if (hiddev->open) {		hid_close(hiddev->hid);		wake_up_interruptible(&hiddev->wait);	} else {		kfree(hiddev);	}}/* Currently this driver is a USB driver.  It's not a conventional one in * the sense that it doesn't probe at the USB level.  Instead it waits to * be connected by HID through the hiddev_connect / hiddev_disconnect * routines.  The reason to register as a USB device is to gain part of the * minor number space from the USB major. * * In theory, should the HID code be generalized to more than one physical * medium (say, IEEE 1384), this driver will probably need to register its * own major number, and in doing so, no longer need to register with USB. * At that point the probe routine and hiddev_driver struct below will no * longer be useful. *//* We never attach in this manner, and rely on HID to connect us.  This * is why there is no disconnect routine defined in the usb_driver either. */static int hiddev_usbd_probe(struct usb_interface *intf,			     const struct usb_device_id *hiddev_info){	return -ENODEV;}static /* const */ struct usb_driver hiddev_driver = {	.owner =	THIS_MODULE,	.name =		"hiddev",	.probe =	hiddev_usbd_probe,};int __init hiddev_init(void){	devfs_mk_dir("usb/hid");	return usb_register(&hiddev_driver);}void hiddev_exit(void){	usb_deregister(&hiddev_driver);	devfs_remove("usb/hid");}

⌨️ 快捷键说明

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