HID: hid-lg4ff: Make lg4ff_wheel_data a separate structure

Make lg4ff_wheel_data a separate structure stored within lg4ff_device_entry.
Adjust the initialization process accordingly.

Signed-off-by: Michal Malý <madcatxster@devoid-pointer.net>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
This commit is contained in:
Michal Malý 2015-04-08 22:56:46 +02:00 committed by Jiri Kosina
parent 2dbf635ea1
commit 72529c65a5
1 changed files with 88 additions and 78 deletions

View File

@ -71,7 +71,7 @@
static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
static void lg4ff_set_range_g25(struct hid_device *hid, u16 range);
struct lg4ff_device_entry {
struct lg4ff_wheel_data {
u32 product_id;
u16 range;
u16 min_range;
@ -84,9 +84,14 @@ struct lg4ff_device_entry {
const char *real_tag;
const char *real_name;
u16 real_product_id;
void (*set_range)(struct hid_device *hid, u16 range);
};
struct lg4ff_device_entry {
struct lg4ff_wheel_data wdata;
};
static const signed short lg4ff_wheel_effects[] = {
FF_CONSTANT,
FF_AUTOCENTER,
@ -278,11 +283,11 @@ int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
return 0;
}
switch (entry->product_id) {
switch (entry->wdata.product_id) {
case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
switch (usage->code) {
case ABS_X:
new_value = lg4ff_adjust_dfp_x_axis(value, entry->range);
new_value = lg4ff_adjust_dfp_x_axis(value, entry->wdata.range);
input_event(field->hidinput->input, usage->type, usage->code, new_value);
return 1;
default:
@ -383,7 +388,7 @@ static void lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude)
}
/* Adjust for non-MOMO wheels */
switch (entry->product_id) {
switch (entry->wdata.product_id) {
case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
break;
@ -605,23 +610,23 @@ static ssize_t lg4ff_alternate_modes_show(struct device *dev, struct device_attr
return 0;
}
if (!entry->real_name) {
if (!entry->wdata.real_name) {
hid_err(hid, "NULL pointer to string\n");
return 0;
}
for (i = 0; i < LG4FF_MODE_MAX_IDX; i++) {
if (entry->alternate_modes & BIT(i)) {
if (entry->wdata.alternate_modes & BIT(i)) {
/* Print tag and full name */
count += scnprintf(buf + count, PAGE_SIZE - count, "%s: %s",
lg4ff_alternate_modes[i].tag,
!lg4ff_alternate_modes[i].product_id ? entry->real_name : lg4ff_alternate_modes[i].name);
!lg4ff_alternate_modes[i].product_id ? entry->wdata.real_name : lg4ff_alternate_modes[i].name);
if (count >= PAGE_SIZE - 1)
return count;
/* Mark the currently active mode with an asterisk */
if (lg4ff_alternate_modes[i].product_id == entry->product_id ||
(lg4ff_alternate_modes[i].product_id == 0 && entry->product_id == entry->real_product_id))
if (lg4ff_alternate_modes[i].product_id == entry->wdata.product_id ||
(lg4ff_alternate_modes[i].product_id == 0 && entry->wdata.product_id == entry->wdata.real_product_id))
count += scnprintf(buf + count, PAGE_SIZE - count, " *\n");
else
count += scnprintf(buf + count, PAGE_SIZE - count, "\n");
@ -674,10 +679,10 @@ static ssize_t lg4ff_alternate_modes_store(struct device *dev, struct device_att
const u16 mode_product_id = lg4ff_alternate_modes[i].product_id;
const char *tag = lg4ff_alternate_modes[i].tag;
if (entry->alternate_modes & BIT(i)) {
if (entry->wdata.alternate_modes & BIT(i)) {
if (!strcmp(tag, lbuf)) {
if (!mode_product_id)
target_product_id = entry->real_product_id;
target_product_id = entry->wdata.real_product_id;
else
target_product_id = mode_product_id;
break;
@ -692,24 +697,24 @@ static ssize_t lg4ff_alternate_modes_store(struct device *dev, struct device_att
}
kfree(lbuf); /* Not needed anymore */
if (target_product_id == entry->product_id) /* Nothing to do */
if (target_product_id == entry->wdata.product_id) /* Nothing to do */
return count;
/* Automatic switching has to be disabled for the switch to DF-EX mode to work correctly */
if (target_product_id == USB_DEVICE_ID_LOGITECH_WHEEL && !lg4ff_no_autoswitch) {
hid_info(hid, "\"%s\" cannot be switched to \"DF-EX\" mode. Load the \"hid_logitech\" module with \"lg4ff_no_autoswitch=1\" parameter set and try again\n",
entry->real_name);
entry->wdata.real_name);
return -EINVAL;
}
/* Take care of hardware limitations */
if ((entry->real_product_id == USB_DEVICE_ID_LOGITECH_DFP_WHEEL || entry->real_product_id == USB_DEVICE_ID_LOGITECH_G25_WHEEL) &&
entry->product_id > target_product_id) {
hid_info(hid, "\"%s\" cannot be switched back into \"%s\" mode\n", entry->real_name, lg4ff_alternate_modes[i].name);
if ((entry->wdata.real_product_id == USB_DEVICE_ID_LOGITECH_DFP_WHEEL || entry->wdata.real_product_id == USB_DEVICE_ID_LOGITECH_G25_WHEEL) &&
entry->wdata.product_id > target_product_id) {
hid_info(hid, "\"%s\" cannot be switched back into \"%s\" mode\n", entry->wdata.real_name, lg4ff_alternate_modes[i].name);
return -EINVAL;
}
s = lg4ff_get_mode_switch_command(entry->real_product_id, target_product_id);
s = lg4ff_get_mode_switch_command(entry->wdata.real_product_id, target_product_id);
if (!s) {
hid_err(hid, "Invalid target product ID %X\n", target_product_id);
return -EINVAL;
@ -741,7 +746,7 @@ static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *att
return 0;
}
count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->range);
count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->wdata.range);
return count;
}
@ -768,13 +773,13 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
}
if (range == 0)
range = entry->max_range;
range = entry->wdata.max_range;
/* Check if the wheel supports range setting
* and that the range is within limits for the wheel */
if (entry->set_range != NULL && range >= entry->min_range && range <= entry->max_range) {
entry->set_range(hid, range);
entry->range = range;
if (entry->wdata.set_range && range >= entry->wdata.min_range && range <= entry->wdata.max_range) {
entry->wdata.set_range(hid, range);
entry->wdata.range = range;
}
return count;
@ -800,12 +805,12 @@ static ssize_t lg4ff_real_id_show(struct device *dev, struct device_attribute *a
return 0;
}
if (!entry->real_tag || !entry->real_name) {
if (!entry->wdata.real_tag || !entry->wdata.real_name) {
hid_err(hid, "NULL pointer to string\n");
return 0;
}
count = scnprintf(buf, PAGE_SIZE, "%s: %s\n", entry->real_tag, entry->real_name);
count = scnprintf(buf, PAGE_SIZE, "%s: %s\n", entry->wdata.real_tag, entry->wdata.real_name);
return count;
}
@ -855,15 +860,15 @@ static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,
}
for (i = 0; i < 5; i++) {
if (led_cdev != entry->led[i])
if (led_cdev != entry->wdata.led[i])
continue;
state = (entry->led_state >> i) & 1;
state = (entry->wdata.led_state >> i) & 1;
if (value == LED_OFF && state) {
entry->led_state &= ~(1 << i);
lg4ff_set_leds(hid, entry->led_state);
entry->wdata.led_state &= ~(1 << i);
lg4ff_set_leds(hid, entry->wdata.led_state);
} else if (value != LED_OFF && !state) {
entry->led_state |= 1 << i;
lg4ff_set_leds(hid, entry->led_state);
entry->wdata.led_state |= 1 << i;
lg4ff_set_leds(hid, entry->wdata.led_state);
}
break;
}
@ -890,8 +895,8 @@ static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cde
}
for (i = 0; i < 5; i++)
if (led_cdev == entry->led[i]) {
value = (entry->led_state >> i) & 1;
if (led_cdev == entry->wdata.led[i]) {
value = (entry->wdata.led_state >> i) & 1;
break;
}
@ -1002,6 +1007,16 @@ int lg4ff_init(struct hid_device *hid)
if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
return -1;
drv_data = hid_get_drvdata(hid);
if (!drv_data) {
hid_err(hid, "Cannot add device, private driver data not allocated\n");
return -1;
}
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
drv_data->device_props = entry;
/* Check if a multimode wheel has been connected and
* handle it appropriately */
mmode_ret = lg4ff_handle_multimode_wheel(hid, &real_product_id, bcdDevice);
@ -1011,6 +1026,11 @@ int lg4ff_init(struct hid_device *hid)
*/
if (mmode_ret == LG4FF_MMODE_SWITCHED)
return 0;
else if (mmode_ret < 0) {
hid_err(hid, "Unable to switch device mode during initialization, errno %d\n", mmode_ret);
error = mmode_ret;
goto err_init;
}
/* Check what wheel has been connected */
for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) {
@ -1024,7 +1044,8 @@ int lg4ff_init(struct hid_device *hid)
hid_err(hid, "This device is flagged to be handled by the lg4ff module but this module does not know how to handle it. "
"Please report this as a bug to LKML, Simon Wood <simon@mungewell.org> or "
"Michal Maly <madcatxster@devoid-pointer.net>\n");
return -1;
error = -1;
goto err_init;
}
if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) {
@ -1035,7 +1056,8 @@ int lg4ff_init(struct hid_device *hid)
if (mmode_idx == ARRAY_SIZE(lg4ff_multimode_wheels)) {
hid_err(hid, "Device product ID %X is not listed as a multimode wheel", real_product_id);
return -1;
error = -1;
goto err_init;
}
}
@ -1046,33 +1068,18 @@ int lg4ff_init(struct hid_device *hid)
error = input_ff_create_memless(dev, NULL, lg4ff_play);
if (error)
return error;
goto err_init;
/* Get private driver data */
drv_data = hid_get_drvdata(hid);
if (!drv_data) {
hid_err(hid, "Cannot add device, private driver data not allocated\n");
return -1;
}
/* Initialize device properties */
entry = kzalloc(sizeof(struct lg4ff_device_entry), GFP_KERNEL);
if (!entry) {
hid_err(hid, "Cannot add device, insufficient memory to allocate device properties.\n");
return -ENOMEM;
}
drv_data->device_props = entry;
entry->product_id = lg4ff_devices[i].product_id;
entry->real_product_id = real_product_id;
entry->min_range = lg4ff_devices[i].min_range;
entry->max_range = lg4ff_devices[i].max_range;
entry->set_range = lg4ff_devices[i].set_range;
entry->wdata.product_id = lg4ff_devices[i].product_id;
entry->wdata.real_product_id = real_product_id;
entry->wdata.min_range = lg4ff_devices[i].min_range;
entry->wdata.max_range = lg4ff_devices[i].max_range;
entry->wdata.set_range = lg4ff_devices[i].set_range;
if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) {
BUG_ON(mmode_idx == -1);
entry->alternate_modes = lg4ff_multimode_wheels[mmode_idx].alternate_modes;
entry->real_tag = lg4ff_multimode_wheels[mmode_idx].real_tag;
entry->real_name = lg4ff_multimode_wheels[mmode_idx].real_name;
entry->wdata.alternate_modes = lg4ff_multimode_wheels[mmode_idx].alternate_modes;
entry->wdata.real_tag = lg4ff_multimode_wheels[mmode_idx].real_tag;
entry->wdata.real_name = lg4ff_multimode_wheels[mmode_idx].real_name;
}
/* Check if autocentering is available and
@ -1091,27 +1098,28 @@ int lg4ff_init(struct hid_device *hid)
/* Create sysfs interface */
error = device_create_file(&hid->dev, &dev_attr_range);
if (error)
return error;
goto err_init;
if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) {
error = device_create_file(&hid->dev, &dev_attr_real_id);
if (error)
return error;
goto err_init;
error = device_create_file(&hid->dev, &dev_attr_alternate_modes);
if (error)
return error;
goto err_init;
}
dbg_hid("sysfs interface created\n");
/* Set the maximum range to start with */
entry->range = entry->max_range;
if (entry->set_range != NULL)
entry->set_range(hid, entry->range);
entry->wdata.range = entry->wdata.max_range;
if (entry->wdata.set_range)
entry->wdata.set_range(hid, entry->wdata.range);
#ifdef CONFIG_LEDS_CLASS
/* register led subsystem - G27 only */
entry->led_state = 0;
entry->wdata.led_state = 0;
for (j = 0; j < 5; j++)
entry->led[j] = NULL;
entry->wdata.led[j] = NULL;
if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL) {
struct led_classdev *led;
@ -1126,7 +1134,7 @@ int lg4ff_init(struct hid_device *hid)
led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
if (!led) {
hid_err(hid, "can't allocate memory for LED %d\n", j);
goto err;
goto err_leds;
}
name = (void *)(&led[1]);
@ -1137,16 +1145,16 @@ int lg4ff_init(struct hid_device *hid)
led->brightness_get = lg4ff_led_get_brightness;
led->brightness_set = lg4ff_led_set_brightness;
entry->led[j] = led;
entry->wdata.led[j] = led;
error = led_classdev_register(&hid->dev, led);
if (error) {
hid_err(hid, "failed to register LED %d. Aborting.\n", j);
err:
err_leds:
/* Deregister LEDs (if any) */
for (j = 0; j < 5; j++) {
led = entry->led[j];
entry->led[j] = NULL;
led = entry->wdata.led[j];
entry->wdata.led[j] = NULL;
if (!led)
continue;
led_classdev_unregister(led);
@ -1160,6 +1168,11 @@ out:
#endif
hid_info(hid, "Force feedback support for Logitech Gaming Wheels\n");
return 0;
err_init:
drv_data->device_props = NULL;
kfree(entry);
return error;
}
int lg4ff_deinit(struct hid_device *hid)
@ -1176,14 +1189,13 @@ int lg4ff_deinit(struct hid_device *hid)
if (!entry)
goto out; /* Nothing more to do */
device_remove_file(&hid->dev, &dev_attr_range);
/* Multimode devices will have at least the "MODE_NATIVE" bit set */
if (entry->alternate_modes) {
if (entry->wdata.alternate_modes) {
device_remove_file(&hid->dev, &dev_attr_real_id);
device_remove_file(&hid->dev, &dev_attr_alternate_modes);
}
device_remove_file(&hid->dev, &dev_attr_range);
#ifdef CONFIG_LEDS_CLASS
{
int j;
@ -1192,8 +1204,8 @@ int lg4ff_deinit(struct hid_device *hid)
/* Deregister LEDs (if any) */
for (j = 0; j < 5; j++) {
led = entry->led[j];
entry->led[j] = NULL;
led = entry->wdata.led[j];
entry->wdata.led[j] = NULL;
if (!led)
continue;
led_classdev_unregister(led);
@ -1202,9 +1214,7 @@ int lg4ff_deinit(struct hid_device *hid)
}
#endif
/* Deallocate memory */
kfree(entry);
out:
dbg_hid("Device successfully unregistered\n");
return 0;