|
@@ -193,6 +193,7 @@ static struct hid_ll_driver logi_dj_ll_driver;
|
|
|
static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
|
|
|
size_t count,
|
|
|
unsigned char report_type);
|
|
|
+static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
|
|
|
|
|
|
static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
|
|
|
struct dj_report *dj_report)
|
|
@@ -233,6 +234,7 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
|
|
|
if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] &
|
|
|
SPFUNCTION_DEVICE_LIST_EMPTY) {
|
|
|
dbg_hid("%s: device list is empty\n", __func__);
|
|
|
+ djrcv_dev->querying_devices = false;
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -243,6 +245,12 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
|
|
|
+ /* The device is already known. No need to reallocate it. */
|
|
|
+ dbg_hid("%s: device is already known\n", __func__);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
dj_hiddev = hid_allocate_device();
|
|
|
if (IS_ERR(dj_hiddev)) {
|
|
|
dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
|
|
@@ -306,6 +314,7 @@ static void delayedwork_callback(struct work_struct *work)
|
|
|
struct dj_report dj_report;
|
|
|
unsigned long flags;
|
|
|
int count;
|
|
|
+ int retval;
|
|
|
|
|
|
dbg_hid("%s\n", __func__);
|
|
|
|
|
@@ -338,6 +347,25 @@ static void delayedwork_callback(struct work_struct *work)
|
|
|
logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report);
|
|
|
break;
|
|
|
default:
|
|
|
+ /* A normal report (i. e. not belonging to a pair/unpair notification)
|
|
|
+ * arriving here, means that the report arrived but we did not have a
|
|
|
+ * paired dj_device associated to the report's device_index, this
|
|
|
+ * means that the original "device paired" notification corresponding
|
|
|
+ * to this dj_device never arrived to this driver. The reason is that
|
|
|
+ * hid-core discards all packets coming from a device while probe() is
|
|
|
+ * executing. */
|
|
|
+ if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) {
|
|
|
+ /* ok, we don't know the device, just re-ask the
|
|
|
+ * receiver for the list of connected devices. */
|
|
|
+ retval = logi_dj_recv_query_paired_devices(djrcv_dev);
|
|
|
+ if (!retval) {
|
|
|
+ /* everything went fine, so just leave */
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ dev_err(&djrcv_dev->hdev->dev,
|
|
|
+ "%s:logi_dj_recv_query_paired_devices "
|
|
|
+ "error:%d\n", __func__, retval);
|
|
|
+ }
|
|
|
dbg_hid("%s: unexpected report type\n", __func__);
|
|
|
}
|
|
|
}
|
|
@@ -368,6 +396,12 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
|
|
|
if (!djdev) {
|
|
|
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
|
|
|
" is NULL, index %d\n", dj_report->device_index);
|
|
|
+ kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
|
|
|
+
|
|
|
+ if (schedule_work(&djrcv_dev->work) == 0) {
|
|
|
+ dbg_hid("%s: did not schedule the work item, was already "
|
|
|
+ "queued\n", __func__);
|
|
|
+ }
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -398,6 +432,12 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
|
|
|
if (dj_device == NULL) {
|
|
|
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
|
|
|
" is NULL, index %d\n", dj_report->device_index);
|
|
|
+ kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
|
|
|
+
|
|
|
+ if (schedule_work(&djrcv_dev->work) == 0) {
|
|
|
+ dbg_hid("%s: did not schedule the work item, was already "
|
|
|
+ "queued\n", __func__);
|
|
|
+ }
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -439,6 +479,10 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
|
|
|
struct dj_report *dj_report;
|
|
|
int retval;
|
|
|
|
|
|
+ /* no need to protect djrcv_dev->querying_devices */
|
|
|
+ if (djrcv_dev->querying_devices)
|
|
|
+ return 0;
|
|
|
+
|
|
|
dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
|
|
|
if (!dj_report)
|
|
|
return -ENOMEM;
|
|
@@ -450,6 +494,7 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
|
|
|
unsigned timeout)
|
|
|
{
|