Commit cf2a299e authored by Jean Delvare's avatar Jean Delvare Committed by Jiri Kosina

HID: fix build failure in hiddev_ioctl with gcc 3.2

Fix build failure in hiddev_ioctl with gcc 3.2:
http://bugzilla.kernel.org/show_bug.cgi?id=10121

The trick is to move the handling of ioctls which need to allocate
memory to separate functions.
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 80750147
...@@ -393,6 +393,153 @@ static unsigned int hiddev_poll(struct file *file, poll_table *wait) ...@@ -393,6 +393,153 @@ static unsigned int hiddev_poll(struct file *file, poll_table *wait)
/* /*
* "ioctl" file op * "ioctl" file op
*/ */
static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg)
{
struct hid_device *hid = hiddev->hid;
struct hiddev_report_info rinfo;
struct hiddev_usage_ref_multi *uref_multi = NULL;
struct hiddev_usage_ref *uref;
struct hid_report *report;
struct hid_field *field;
int i;
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;
}
switch (cmd) {
case HIDIOCGUCODE:
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;
default:
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;
}
}
static noinline int hiddev_ioctl_string(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg)
{
struct hid_device *hid = hiddev->hid;
struct usb_device *dev = hid_to_usb_dev(hid);
int idx, len;
char *buf;
if (get_user(idx, (int __user *)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;
}
static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 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_list *list = file->private_data;
...@@ -402,8 +549,6 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -402,8 +549,6 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
struct hiddev_collection_info cinfo; struct hiddev_collection_info cinfo;
struct hiddev_report_info rinfo; struct hiddev_report_info rinfo;
struct hiddev_field_info finfo; struct hiddev_field_info finfo;
struct hiddev_usage_ref_multi *uref_multi = NULL;
struct hiddev_usage_ref *uref;
struct hiddev_devinfo dinfo; struct hiddev_devinfo dinfo;
struct hid_report *report; struct hid_report *report;
struct hid_field *field; struct hid_field *field;
...@@ -470,30 +615,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -470,30 +615,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
} }
case HIDIOCGSTRING: case HIDIOCGSTRING:
{ return hiddev_ioctl_string(hiddev, cmd, user_arg);
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: case HIDIOCINITREPORT:
usbhid_init_reports(hid); usbhid_init_reports(hid);
...@@ -578,121 +700,13 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -578,121 +700,13 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return 0; return 0;
case HIDIOCGUCODE: case HIDIOCGUCODE:
uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); /* fall through */
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 HIDIOCGUSAGE:
case HIDIOCSUSAGE: case HIDIOCSUSAGE:
case HIDIOCGUSAGES: case HIDIOCGUSAGES:
case HIDIOCSUSAGES: case HIDIOCSUSAGES:
case HIDIOCGCOLLECTIONINDEX: case HIDIOCGCOLLECTIONINDEX:
uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); return hiddev_ioctl_usage(hiddev, cmd, user_arg);
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: case HIDIOCGCOLLECTIONINFO:
if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment