diff options
| -rw-r--r-- | drivers/hid/hid-lg4ff.c | 92 |
1 files changed, 42 insertions, 50 deletions
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 11452920a6c3..32c173fcb7f8 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c | |||
| @@ -51,10 +51,7 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at | |||
| 51 | 51 | ||
| 52 | static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store); | 52 | static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store); |
| 53 | 53 | ||
| 54 | static bool list_inited; | ||
| 55 | |||
| 56 | struct lg4ff_device_entry { | 54 | struct lg4ff_device_entry { |
| 57 | char *device_id; /* Use name in respective kobject structure's address as the ID */ | ||
| 58 | __u16 range; | 55 | __u16 range; |
| 59 | __u16 min_range; | 56 | __u16 min_range; |
| 60 | __u16 max_range; | 57 | __u16 max_range; |
| @@ -63,8 +60,6 @@ struct lg4ff_device_entry { | |||
| 63 | void (*set_range)(struct hid_device *hid, u16 range); | 60 | void (*set_range)(struct hid_device *hid, u16 range); |
| 64 | }; | 61 | }; |
| 65 | 62 | ||
| 66 | static struct lg4ff_device_entry device_list; | ||
| 67 | |||
| 68 | static const signed short lg4ff_wheel_effects[] = { | 63 | static const signed short lg4ff_wheel_effects[] = { |
| 69 | FF_CONSTANT, | 64 | FF_CONSTANT, |
| 70 | FF_AUTOCENTER, | 65 | FF_AUTOCENTER, |
| @@ -285,18 +280,20 @@ static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_n | |||
| 285 | /* Read current range and display it in terminal */ | 280 | /* Read current range and display it in terminal */ |
| 286 | static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf) | 281 | static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 287 | { | 282 | { |
| 288 | struct lg4ff_device_entry *uninitialized_var(entry); | ||
| 289 | struct list_head *h; | ||
| 290 | struct hid_device *hid = to_hid_device(dev); | 283 | struct hid_device *hid = to_hid_device(dev); |
| 284 | struct lg4ff_device_entry *entry; | ||
| 285 | struct lg_drv_data *drv_data; | ||
| 291 | size_t count; | 286 | size_t count; |
| 292 | 287 | ||
| 293 | list_for_each(h, &device_list.list) { | 288 | drv_data = hid_get_drvdata(hid); |
| 294 | entry = list_entry(h, struct lg4ff_device_entry, list); | 289 | if (!drv_data) { |
| 295 | if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0) | 290 | hid_err(hid, "Private driver data not found!\n"); |
| 296 | break; | 291 | return 0; |
| 297 | } | 292 | } |
| 298 | if (h == &device_list.list) { | 293 | |
| 299 | dbg_hid("Device not found!"); | 294 | entry = drv_data->device_props; |
| 295 | if (!entry) { | ||
| 296 | hid_err(hid, "Device properties not found!\n"); | ||
| 300 | return 0; | 297 | return 0; |
| 301 | } | 298 | } |
| 302 | 299 | ||
| @@ -308,19 +305,21 @@ static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *att | |||
| 308 | * according to the type of the wheel */ | 305 | * according to the type of the wheel */ |
| 309 | static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 306 | static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
| 310 | { | 307 | { |
| 311 | struct lg4ff_device_entry *uninitialized_var(entry); | ||
| 312 | struct list_head *h; | ||
| 313 | struct hid_device *hid = to_hid_device(dev); | 308 | struct hid_device *hid = to_hid_device(dev); |
| 309 | struct lg4ff_device_entry *entry; | ||
| 310 | struct lg_drv_data *drv_data; | ||
| 314 | __u16 range = simple_strtoul(buf, NULL, 10); | 311 | __u16 range = simple_strtoul(buf, NULL, 10); |
| 315 | 312 | ||
| 316 | list_for_each(h, &device_list.list) { | 313 | drv_data = hid_get_drvdata(hid); |
| 317 | entry = list_entry(h, struct lg4ff_device_entry, list); | 314 | if (!drv_data) { |
| 318 | if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0) | 315 | hid_err(hid, "Private driver data not found!\n"); |
| 319 | break; | 316 | return 0; |
| 320 | } | 317 | } |
| 321 | if (h == &device_list.list) { | 318 | |
| 322 | dbg_hid("Device not found!"); | 319 | entry = drv_data->device_props; |
| 323 | return count; | 320 | if (!entry) { |
| 321 | hid_err(hid, "Device properties not found!\n"); | ||
| 322 | return 0; | ||
| 324 | } | 323 | } |
| 325 | 324 | ||
| 326 | if (range == 0) | 325 | if (range == 0) |
| @@ -344,6 +343,7 @@ int lg4ff_init(struct hid_device *hid) | |||
| 344 | struct hid_report *report; | 343 | struct hid_report *report; |
| 345 | struct hid_field *field; | 344 | struct hid_field *field; |
| 346 | struct lg4ff_device_entry *entry; | 345 | struct lg4ff_device_entry *entry; |
| 346 | struct lg_drv_data *drv_data; | ||
| 347 | struct usb_device_descriptor *udesc; | 347 | struct usb_device_descriptor *udesc; |
| 348 | int error, i, j; | 348 | int error, i, j; |
| 349 | __u16 bcdDevice, rev_maj, rev_min; | 349 | __u16 bcdDevice, rev_maj, rev_min; |
| @@ -423,28 +423,24 @@ int lg4ff_init(struct hid_device *hid) | |||
| 423 | dev->ff->set_autocenter(dev, 0); | 423 | dev->ff->set_autocenter(dev, 0); |
| 424 | } | 424 | } |
| 425 | 425 | ||
| 426 | /* Initialize device_list if this is the first device to handle by lg4ff */ | 426 | /* Get private driver data */ |
| 427 | if (!list_inited) { | 427 | drv_data = hid_get_drvdata(hid); |
| 428 | INIT_LIST_HEAD(&device_list.list); | 428 | if (!drv_data) { |
| 429 | list_inited = 1; | 429 | hid_err(hid, "Cannot add device, private driver data not allocated\n"); |
| 430 | return -1; | ||
| 430 | } | 431 | } |
| 431 | 432 | ||
| 432 | /* Add the device to device_list */ | 433 | /* Initialize device properties */ |
| 433 | entry = kzalloc(sizeof(struct lg4ff_device_entry), GFP_KERNEL); | 434 | entry = kzalloc(sizeof(struct lg4ff_device_entry), GFP_KERNEL); |
| 434 | if (!entry) { | 435 | if (!entry) { |
| 435 | hid_err(hid, "Cannot add device, insufficient memory.\n"); | 436 | hid_err(hid, "Cannot add device, insufficient memory to allocate device properties.\n"); |
| 436 | return -ENOMEM; | ||
| 437 | } | ||
| 438 | entry->device_id = kstrdup((&hid->dev)->kobj.name, GFP_KERNEL); | ||
| 439 | if (!entry->device_id) { | ||
| 440 | hid_err(hid, "Cannot set device_id, insufficient memory.\n"); | ||
| 441 | kfree(entry); | ||
| 442 | return -ENOMEM; | 437 | return -ENOMEM; |
| 443 | } | 438 | } |
| 439 | drv_data->device_props = entry; | ||
| 440 | |||
| 444 | entry->min_range = lg4ff_devices[i].min_range; | 441 | entry->min_range = lg4ff_devices[i].min_range; |
| 445 | entry->max_range = lg4ff_devices[i].max_range; | 442 | entry->max_range = lg4ff_devices[i].max_range; |
| 446 | entry->set_range = lg4ff_devices[i].set_range; | 443 | entry->set_range = lg4ff_devices[i].set_range; |
| 447 | list_add(&entry->list, &device_list.list); | ||
| 448 | 444 | ||
| 449 | /* Create sysfs interface */ | 445 | /* Create sysfs interface */ |
| 450 | error = device_create_file(&hid->dev, &dev_attr_range); | 446 | error = device_create_file(&hid->dev, &dev_attr_range); |
| @@ -463,27 +459,23 @@ int lg4ff_init(struct hid_device *hid) | |||
| 463 | 459 | ||
| 464 | int lg4ff_deinit(struct hid_device *hid) | 460 | int lg4ff_deinit(struct hid_device *hid) |
| 465 | { | 461 | { |
| 466 | bool found = 0; | ||
| 467 | struct lg4ff_device_entry *entry; | 462 | struct lg4ff_device_entry *entry; |
| 468 | struct list_head *h, *g; | 463 | struct lg_drv_data *drv_data; |
| 469 | 464 | ||
| 470 | device_remove_file(&hid->dev, &dev_attr_range); | 465 | device_remove_file(&hid->dev, &dev_attr_range); |
| 471 | 466 | ||
| 472 | list_for_each_safe(h, g, &device_list.list) { | 467 | drv_data = hid_get_drvdata(hid); |
| 473 | entry = list_entry(h, struct lg4ff_device_entry, list); | 468 | if (!drv_data) { |
| 474 | if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0) { | 469 | hid_err(hid, "Error while deinitializing device, no private driver data.\n"); |
| 475 | list_del(h); | 470 | return -1; |
| 476 | kfree(entry->device_id); | ||
| 477 | kfree(entry); | ||
| 478 | found = 1; | ||
| 479 | break; | ||
| 480 | } | ||
| 481 | } | 471 | } |
| 482 | 472 | entry = drv_data->device_props; | |
| 483 | if (!found) { | 473 | if (!entry) { |
| 484 | hid_err(hid, "Device entry not found!\n"); | 474 | hid_err(hid, "Error while deinitializing device, no device properties data.\n"); |
| 485 | return -1; | 475 | return -1; |
| 486 | } | 476 | } |
| 477 | /* Deallocate memory */ | ||
| 478 | kfree(entry); | ||
| 487 | 479 | ||
| 488 | dbg_hid("Device successfully unregistered\n"); | 480 | dbg_hid("Device successfully unregistered\n"); |
| 489 | return 0; | 481 | return 0; |
