Commit e6dfb043 authored by Jiri Kosina's avatar Jiri Kosina

Merge branches 'for-3.11/upstream-fixes' and 'for-3.11/logitech-enumeration-fix' into for-linus

parents 8e552e53 407a2c2a
...@@ -192,6 +192,7 @@ static struct hid_ll_driver logi_dj_ll_driver; ...@@ -192,6 +192,7 @@ static struct hid_ll_driver logi_dj_ll_driver;
static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf, static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
size_t count, size_t count,
unsigned char report_type); 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, static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
struct dj_report *dj_report) struct dj_report *dj_report)
...@@ -232,6 +233,7 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, ...@@ -232,6 +233,7 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] & if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] &
SPFUNCTION_DEVICE_LIST_EMPTY) { SPFUNCTION_DEVICE_LIST_EMPTY) {
dbg_hid("%s: device list is empty\n", __func__); dbg_hid("%s: device list is empty\n", __func__);
djrcv_dev->querying_devices = false;
return; return;
} }
...@@ -242,6 +244,12 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, ...@@ -242,6 +244,12 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
return; 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(); dj_hiddev = hid_allocate_device();
if (IS_ERR(dj_hiddev)) { if (IS_ERR(dj_hiddev)) {
dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n", dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
...@@ -305,6 +313,7 @@ static void delayedwork_callback(struct work_struct *work) ...@@ -305,6 +313,7 @@ static void delayedwork_callback(struct work_struct *work)
struct dj_report dj_report; struct dj_report dj_report;
unsigned long flags; unsigned long flags;
int count; int count;
int retval;
dbg_hid("%s\n", __func__); dbg_hid("%s\n", __func__);
...@@ -337,6 +346,25 @@ static void delayedwork_callback(struct work_struct *work) ...@@ -337,6 +346,25 @@ static void delayedwork_callback(struct work_struct *work)
logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report); logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report);
break; break;
default: 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__); dbg_hid("%s: unexpected report type\n", __func__);
} }
} }
...@@ -367,6 +395,12 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev, ...@@ -367,6 +395,12 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
if (!djdev) { if (!djdev) {
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
" is NULL, index %d\n", 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; return;
} }
...@@ -397,6 +431,12 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev, ...@@ -397,6 +431,12 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
if (dj_device == NULL) { if (dj_device == NULL) {
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
" is NULL, index %d\n", 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; return;
} }
...@@ -444,6 +484,12 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) ...@@ -444,6 +484,12 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
struct dj_report *dj_report; struct dj_report *dj_report;
int retval; int retval;
/* no need to protect djrcv_dev->querying_devices */
if (djrcv_dev->querying_devices)
return 0;
djrcv_dev->querying_devices = true;
dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL); dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
if (!dj_report) if (!dj_report)
return -ENOMEM; return -ENOMEM;
...@@ -455,6 +501,7 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) ...@@ -455,6 +501,7 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
return retval; return retval;
} }
static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
unsigned timeout) unsigned timeout)
{ {
......
...@@ -101,6 +101,7 @@ struct dj_receiver_dev { ...@@ -101,6 +101,7 @@ struct dj_receiver_dev {
struct work_struct work; struct work_struct work;
struct kfifo notif_fifo; struct kfifo notif_fifo;
spinlock_t lock; spinlock_t lock;
bool querying_devices;
}; };
struct dj_device { struct dj_device {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment