diff options
author | Michal Malý <madcatxster@gmail.com> | 2012-03-31 05:17:25 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2012-04-02 22:09:50 -0400 |
commit | 8577dbf9d6eb07213caefb49e2017c177c5f023d (patch) | |
tree | 2c22ad4bad6a927220f76ab157b65d902deb8288 /drivers/hid/hid-lg.c | |
parent | d464c92b5234227c1698862a1906827e2e398ae0 (diff) |
HID: hid-lg: Allow for custom device-specific properties to be stored in priv drvdata
This patch adds support for custom device-specific properties which can now be
stored as private driver data and read/saved using hid_get/set_drvdata().
Signed-off-by: Michal Malý <madcatxster@gmail.com>
Tested-by: simon@mungewell.org
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-lg.c')
-rw-r--r-- | drivers/hid/hid-lg.c | 55 |
1 files changed, 32 insertions, 23 deletions
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index e7a7bd1eb34a..fc37ed6b108c 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c | |||
@@ -109,23 +109,23 @@ static __u8 dfp_rdesc_fixed[] = { | |||
109 | static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, | 109 | static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, |
110 | unsigned int *rsize) | 110 | unsigned int *rsize) |
111 | { | 111 | { |
112 | unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); | 112 | struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); |
113 | 113 | ||
114 | if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 && | 114 | if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 && |
115 | rdesc[84] == 0x8c && rdesc[85] == 0x02) { | 115 | rdesc[84] == 0x8c && rdesc[85] == 0x02) { |
116 | hid_info(hdev, | 116 | hid_info(hdev, |
117 | "fixing up Logitech keyboard report descriptor\n"); | 117 | "fixing up Logitech keyboard report descriptor\n"); |
118 | rdesc[84] = rdesc[89] = 0x4d; | 118 | rdesc[84] = rdesc[89] = 0x4d; |
119 | rdesc[85] = rdesc[90] = 0x10; | 119 | rdesc[85] = rdesc[90] = 0x10; |
120 | } | 120 | } |
121 | if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 && | 121 | if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 && |
122 | rdesc[32] == 0x81 && rdesc[33] == 0x06 && | 122 | rdesc[32] == 0x81 && rdesc[33] == 0x06 && |
123 | rdesc[49] == 0x81 && rdesc[50] == 0x06) { | 123 | rdesc[49] == 0x81 && rdesc[50] == 0x06) { |
124 | hid_info(hdev, | 124 | hid_info(hdev, |
125 | "fixing up rel/abs in Logitech report descriptor\n"); | 125 | "fixing up rel/abs in Logitech report descriptor\n"); |
126 | rdesc[33] = rdesc[50] = 0x02; | 126 | rdesc[33] = rdesc[50] = 0x02; |
127 | } | 127 | } |
128 | if ((quirks & LG_FF4) && *rsize >= 101 && | 128 | if ((drv_data->quirks & LG_FF4) && *rsize >= 101 && |
129 | rdesc[41] == 0x95 && rdesc[42] == 0x0B && | 129 | rdesc[41] == 0x95 && rdesc[42] == 0x0B && |
130 | rdesc[47] == 0x05 && rdesc[48] == 0x09) { | 130 | rdesc[47] == 0x05 && rdesc[48] == 0x09) { |
131 | hid_info(hdev, "fixing up Logitech Speed Force Wireless button descriptor\n"); | 131 | hid_info(hdev, "fixing up Logitech Speed Force Wireless button descriptor\n"); |
@@ -278,7 +278,7 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
278 | 0, 0, 0, 0, 0,183,184,185,186,187, | 278 | 0, 0, 0, 0, 0,183,184,185,186,187, |
279 | 188,189,190,191,192,193,194, 0, 0, 0 | 279 | 188,189,190,191,192,193,194, 0, 0, 0 |
280 | }; | 280 | }; |
281 | unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); | 281 | struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); |
282 | unsigned int hid = usage->hid; | 282 | unsigned int hid = usage->hid; |
283 | 283 | ||
284 | if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER && | 284 | if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER && |
@@ -289,7 +289,7 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
289 | lg_dinovo_mapping(hi, usage, bit, max)) | 289 | lg_dinovo_mapping(hi, usage, bit, max)) |
290 | return 1; | 290 | return 1; |
291 | 291 | ||
292 | if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max)) | 292 | if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max)) |
293 | return 1; | 293 | return 1; |
294 | 294 | ||
295 | if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON) | 295 | if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON) |
@@ -299,11 +299,11 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
299 | 299 | ||
300 | /* Special handling for Logitech Cordless Desktop */ | 300 | /* Special handling for Logitech Cordless Desktop */ |
301 | if (field->application == HID_GD_MOUSE) { | 301 | if (field->application == HID_GD_MOUSE) { |
302 | if ((quirks & LG_IGNORE_DOUBLED_WHEEL) && | 302 | if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) && |
303 | (hid == 7 || hid == 8)) | 303 | (hid == 7 || hid == 8)) |
304 | return -1; | 304 | return -1; |
305 | } else { | 305 | } else { |
306 | if ((quirks & LG_EXPANDED_KEYMAP) && | 306 | if ((drv_data->quirks & LG_EXPANDED_KEYMAP) && |
307 | hid < ARRAY_SIZE(e_keymap) && | 307 | hid < ARRAY_SIZE(e_keymap) && |
308 | e_keymap[hid] != 0) { | 308 | e_keymap[hid] != 0) { |
309 | hid_map_usage(hi, usage, bit, max, EV_KEY, | 309 | hid_map_usage(hi, usage, bit, max, EV_KEY, |
@@ -319,13 +319,13 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi, | |||
319 | struct hid_field *field, struct hid_usage *usage, | 319 | struct hid_field *field, struct hid_usage *usage, |
320 | unsigned long **bit, int *max) | 320 | unsigned long **bit, int *max) |
321 | { | 321 | { |
322 | unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); | 322 | struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); |
323 | 323 | ||
324 | if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY && | 324 | if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY && |
325 | (field->flags & HID_MAIN_ITEM_RELATIVE)) | 325 | (field->flags & HID_MAIN_ITEM_RELATIVE)) |
326 | field->flags &= ~HID_MAIN_ITEM_RELATIVE; | 326 | field->flags &= ~HID_MAIN_ITEM_RELATIVE; |
327 | 327 | ||
328 | if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY || | 328 | if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY || |
329 | usage->type == EV_REL || usage->type == EV_ABS)) | 329 | usage->type == EV_REL || usage->type == EV_ABS)) |
330 | clear_bit(usage->code, *bit); | 330 | clear_bit(usage->code, *bit); |
331 | 331 | ||
@@ -335,9 +335,9 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi, | |||
335 | static int lg_event(struct hid_device *hdev, struct hid_field *field, | 335 | static int lg_event(struct hid_device *hdev, struct hid_field *field, |
336 | struct hid_usage *usage, __s32 value) | 336 | struct hid_usage *usage, __s32 value) |
337 | { | 337 | { |
338 | unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); | 338 | struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); |
339 | 339 | ||
340 | if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) { | 340 | if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) { |
341 | input_event(field->hidinput->input, usage->type, usage->code, | 341 | input_event(field->hidinput->input, usage->type, usage->code, |
342 | -value); | 342 | -value); |
343 | return 1; | 343 | return 1; |
@@ -348,13 +348,20 @@ static int lg_event(struct hid_device *hdev, struct hid_field *field, | |||
348 | 348 | ||
349 | static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) | 349 | static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) |
350 | { | 350 | { |
351 | unsigned long quirks = id->driver_data; | ||
352 | unsigned int connect_mask = HID_CONNECT_DEFAULT; | 351 | unsigned int connect_mask = HID_CONNECT_DEFAULT; |
352 | struct lg_drv_data *drv_data; | ||
353 | int ret; | 353 | int ret; |
354 | 354 | ||
355 | hid_set_drvdata(hdev, (void *)quirks); | 355 | drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL); |
356 | if (!drv_data) { | ||
357 | hid_err(hdev, "Insufficient memory, cannot allocate driver data\n"); | ||
358 | return -ENOMEM; | ||
359 | } | ||
360 | drv_data->quirks = id->driver_data; | ||
361 | |||
362 | hid_set_drvdata(hdev, (void *)drv_data); | ||
356 | 363 | ||
357 | if (quirks & LG_NOGET) | 364 | if (drv_data->quirks & LG_NOGET) |
358 | hdev->quirks |= HID_QUIRK_NOGET; | 365 | hdev->quirks |= HID_QUIRK_NOGET; |
359 | 366 | ||
360 | ret = hid_parse(hdev); | 367 | ret = hid_parse(hdev); |
@@ -363,7 +370,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
363 | goto err_free; | 370 | goto err_free; |
364 | } | 371 | } |
365 | 372 | ||
366 | if (quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4)) | 373 | if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4)) |
367 | connect_mask &= ~HID_CONNECT_FF; | 374 | connect_mask &= ~HID_CONNECT_FF; |
368 | 375 | ||
369 | ret = hid_hw_start(hdev, connect_mask); | 376 | ret = hid_hw_start(hdev, connect_mask); |
@@ -392,27 +399,29 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
392 | } | 399 | } |
393 | } | 400 | } |
394 | 401 | ||
395 | if (quirks & LG_FF) | 402 | if (drv_data->quirks & LG_FF) |
396 | lgff_init(hdev); | 403 | lgff_init(hdev); |
397 | if (quirks & LG_FF2) | 404 | if (drv_data->quirks & LG_FF2) |
398 | lg2ff_init(hdev); | 405 | lg2ff_init(hdev); |
399 | if (quirks & LG_FF3) | 406 | if (drv_data->quirks & LG_FF3) |
400 | lg3ff_init(hdev); | 407 | lg3ff_init(hdev); |
401 | if (quirks & LG_FF4) | 408 | if (drv_data->quirks & LG_FF4) |
402 | lg4ff_init(hdev); | 409 | lg4ff_init(hdev); |
403 | 410 | ||
404 | return 0; | 411 | return 0; |
405 | err_free: | 412 | err_free: |
413 | kfree(drv_data); | ||
406 | return ret; | 414 | return ret; |
407 | } | 415 | } |
408 | 416 | ||
409 | static void lg_remove(struct hid_device *hdev) | 417 | static void lg_remove(struct hid_device *hdev) |
410 | { | 418 | { |
411 | unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); | 419 | struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev); |
412 | if(quirks & LG_FF4) | 420 | if (drv_data->quirks & LG_FF4) |
413 | lg4ff_deinit(hdev); | 421 | lg4ff_deinit(hdev); |
414 | 422 | ||
415 | hid_hw_stop(hdev); | 423 | hid_hw_stop(hdev); |
424 | kfree(drv_data); | ||
416 | } | 425 | } |
417 | 426 | ||
418 | static const struct hid_device_id lg_devices[] = { | 427 | static const struct hid_device_id lg_devices[] = { |