diff options
| -rw-r--r-- | drivers/hid/hid-logitech-dj.c | 47 | ||||
| -rw-r--r-- | drivers/hid/hid-logitech-dj.h | 1 | ||||
| -rw-r--r-- | drivers/hid/hid-sony.c | 3 | ||||
| -rw-r--r-- | drivers/hid/hidraw.c | 2 |
4 files changed, 51 insertions, 2 deletions
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 5207591a598c..7a5764843bfb 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c | |||
| @@ -192,6 +192,7 @@ static struct hid_ll_driver logi_dj_ll_driver; | |||
| 192 | static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf, | 192 | static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf, |
| 193 | size_t count, | 193 | size_t count, |
| 194 | unsigned char report_type); | 194 | unsigned char report_type); |
| 195 | static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev); | ||
| 195 | 196 | ||
| 196 | static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev, | 197 | static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev, |
| 197 | struct dj_report *dj_report) | 198 | struct dj_report *dj_report) |
| @@ -232,6 +233,7 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, | |||
| 232 | if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] & | 233 | if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] & |
| 233 | SPFUNCTION_DEVICE_LIST_EMPTY) { | 234 | SPFUNCTION_DEVICE_LIST_EMPTY) { |
| 234 | dbg_hid("%s: device list is empty\n", __func__); | 235 | dbg_hid("%s: device list is empty\n", __func__); |
| 236 | djrcv_dev->querying_devices = false; | ||
| 235 | return; | 237 | return; |
| 236 | } | 238 | } |
| 237 | 239 | ||
| @@ -242,6 +244,12 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, | |||
| 242 | return; | 244 | return; |
| 243 | } | 245 | } |
| 244 | 246 | ||
| 247 | if (djrcv_dev->paired_dj_devices[dj_report->device_index]) { | ||
| 248 | /* The device is already known. No need to reallocate it. */ | ||
| 249 | dbg_hid("%s: device is already known\n", __func__); | ||
| 250 | return; | ||
| 251 | } | ||
| 252 | |||
| 245 | dj_hiddev = hid_allocate_device(); | 253 | dj_hiddev = hid_allocate_device(); |
| 246 | if (IS_ERR(dj_hiddev)) { | 254 | if (IS_ERR(dj_hiddev)) { |
| 247 | dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n", | 255 | dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n", |
| @@ -305,6 +313,7 @@ static void delayedwork_callback(struct work_struct *work) | |||
| 305 | struct dj_report dj_report; | 313 | struct dj_report dj_report; |
| 306 | unsigned long flags; | 314 | unsigned long flags; |
| 307 | int count; | 315 | int count; |
| 316 | int retval; | ||
| 308 | 317 | ||
| 309 | dbg_hid("%s\n", __func__); | 318 | dbg_hid("%s\n", __func__); |
| 310 | 319 | ||
| @@ -337,6 +346,25 @@ static void delayedwork_callback(struct work_struct *work) | |||
| 337 | logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report); | 346 | logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report); |
| 338 | break; | 347 | break; |
| 339 | default: | 348 | default: |
| 349 | /* A normal report (i. e. not belonging to a pair/unpair notification) | ||
| 350 | * arriving here, means that the report arrived but we did not have a | ||
| 351 | * paired dj_device associated to the report's device_index, this | ||
| 352 | * means that the original "device paired" notification corresponding | ||
| 353 | * to this dj_device never arrived to this driver. The reason is that | ||
| 354 | * hid-core discards all packets coming from a device while probe() is | ||
| 355 | * executing. */ | ||
| 356 | if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) { | ||
| 357 | /* ok, we don't know the device, just re-ask the | ||
| 358 | * receiver for the list of connected devices. */ | ||
| 359 | retval = logi_dj_recv_query_paired_devices(djrcv_dev); | ||
| 360 | if (!retval) { | ||
| 361 | /* everything went fine, so just leave */ | ||
| 362 | break; | ||
| 363 | } | ||
| 364 | dev_err(&djrcv_dev->hdev->dev, | ||
| 365 | "%s:logi_dj_recv_query_paired_devices " | ||
| 366 | "error:%d\n", __func__, retval); | ||
| 367 | } | ||
| 340 | dbg_hid("%s: unexpected report type\n", __func__); | 368 | dbg_hid("%s: unexpected report type\n", __func__); |
| 341 | } | 369 | } |
| 342 | } | 370 | } |
| @@ -367,6 +395,12 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev, | |||
| 367 | if (!djdev) { | 395 | if (!djdev) { |
| 368 | dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" | 396 | dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" |
| 369 | " is NULL, index %d\n", dj_report->device_index); | 397 | " is NULL, index %d\n", dj_report->device_index); |
| 398 | kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report)); | ||
| 399 | |||
| 400 | if (schedule_work(&djrcv_dev->work) == 0) { | ||
| 401 | dbg_hid("%s: did not schedule the work item, was already " | ||
| 402 | "queued\n", __func__); | ||
| 403 | } | ||
| 370 | return; | 404 | return; |
| 371 | } | 405 | } |
| 372 | 406 | ||
| @@ -397,6 +431,12 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev, | |||
| 397 | if (dj_device == NULL) { | 431 | if (dj_device == NULL) { |
| 398 | dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" | 432 | dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" |
| 399 | " is NULL, index %d\n", dj_report->device_index); | 433 | " is NULL, index %d\n", dj_report->device_index); |
| 434 | kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report)); | ||
| 435 | |||
| 436 | if (schedule_work(&djrcv_dev->work) == 0) { | ||
| 437 | dbg_hid("%s: did not schedule the work item, was already " | ||
| 438 | "queued\n", __func__); | ||
| 439 | } | ||
| 400 | return; | 440 | return; |
| 401 | } | 441 | } |
| 402 | 442 | ||
| @@ -444,6 +484,12 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) | |||
| 444 | struct dj_report *dj_report; | 484 | struct dj_report *dj_report; |
| 445 | int retval; | 485 | int retval; |
| 446 | 486 | ||
| 487 | /* no need to protect djrcv_dev->querying_devices */ | ||
| 488 | if (djrcv_dev->querying_devices) | ||
| 489 | return 0; | ||
| 490 | |||
| 491 | djrcv_dev->querying_devices = true; | ||
| 492 | |||
| 447 | dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL); | 493 | dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL); |
| 448 | if (!dj_report) | 494 | if (!dj_report) |
| 449 | return -ENOMEM; | 495 | return -ENOMEM; |
| @@ -455,6 +501,7 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) | |||
| 455 | return retval; | 501 | return retval; |
| 456 | } | 502 | } |
| 457 | 503 | ||
| 504 | |||
| 458 | static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, | 505 | static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, |
| 459 | unsigned timeout) | 506 | unsigned timeout) |
| 460 | { | 507 | { |
diff --git a/drivers/hid/hid-logitech-dj.h b/drivers/hid/hid-logitech-dj.h index fd28a5e0ca3b..4a4000340ce1 100644 --- a/drivers/hid/hid-logitech-dj.h +++ b/drivers/hid/hid-logitech-dj.h | |||
| @@ -101,6 +101,7 @@ struct dj_receiver_dev { | |||
| 101 | struct work_struct work; | 101 | struct work_struct work; |
| 102 | struct kfifo notif_fifo; | 102 | struct kfifo notif_fifo; |
| 103 | spinlock_t lock; | 103 | spinlock_t lock; |
| 104 | bool querying_devices; | ||
| 104 | }; | 105 | }; |
| 105 | 106 | ||
| 106 | struct dj_device { | 107 | struct dj_device { |
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index ecbc74923d06..87fbe2924cfa 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c | |||
| @@ -369,7 +369,8 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
| 369 | if (sc->quirks & PS3REMOTE) | 369 | if (sc->quirks & PS3REMOTE) |
| 370 | return ps3remote_mapping(hdev, hi, field, usage, bit, max); | 370 | return ps3remote_mapping(hdev, hi, field, usage, bit, max); |
| 371 | 371 | ||
| 372 | return -1; | 372 | /* Let hid-core decide for the others */ |
| 373 | return 0; | ||
| 373 | } | 374 | } |
| 374 | 375 | ||
| 375 | /* | 376 | /* |
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index a7451632ceb4..6f1feb2c2e97 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c | |||
| @@ -518,7 +518,6 @@ int hidraw_connect(struct hid_device *hid) | |||
| 518 | goto out; | 518 | goto out; |
| 519 | } | 519 | } |
| 520 | 520 | ||
| 521 | mutex_unlock(&minors_lock); | ||
| 522 | init_waitqueue_head(&dev->wait); | 521 | init_waitqueue_head(&dev->wait); |
| 523 | INIT_LIST_HEAD(&dev->list); | 522 | INIT_LIST_HEAD(&dev->list); |
| 524 | 523 | ||
| @@ -528,6 +527,7 @@ int hidraw_connect(struct hid_device *hid) | |||
| 528 | dev->exist = 1; | 527 | dev->exist = 1; |
| 529 | hid->hidraw = dev; | 528 | hid->hidraw = dev; |
| 530 | 529 | ||
| 530 | mutex_unlock(&minors_lock); | ||
| 531 | out: | 531 | out: |
| 532 | return result; | 532 | return result; |
| 533 | 533 | ||
