[PATCH 2/3] Add support for specific device methods.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds hook into the code to add support for specific
device driver. The right driver is select on the basis of the name.

4 hooks are added:
- init_device()	called during the device initialization
- parse()       called during the device description generation phase
- parse_raw_event() which handles the events from the device
- destroy()	called when the device is destroyed

The construction of the device is dived in two phases:
1) the device is discovered by the receiver. The struct dj_device
is allocated BUT the device is not enabled.
It is asked the device name top the device itself
2) when the device name arrived from the device, the
the right driver is selected, structure dj_device is finalized,
the hid-device id created.
If the device name returned doesn't match, the generic driver
(e.g. the one provided until now) is used.


Signed-off-by: Goffredo Baroncelli <kreijack@xxxxxxxxx>
---
 drivers/hid/hid-logitech-dj.c | 422 ++++++++++++++++++++++++++++++++++--------
 drivers/hid/hid-logitech-dj.h |  41 ++++
 2 files changed, 388 insertions(+), 75 deletions(-)

diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index ca0ab51..feddd3d 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -193,7 +193,51 @@ static const u8 hid_reportid_size_map[NUMBER_OF_HID_REPORTS] = {
 
 static struct hid_ll_driver logi_dj_ll_driver;
 
+static inline struct dj_device *logi_djrcv2djdev(
+					struct dj_receiver_dev *djrcv_dev,
+					int index);
 static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
+static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
+				    struct dj_report *dj_report);
+
+static inline int call_init_device(struct dj_device *djdev)
+{
+	if (!djdev || !djdev->methods || !djdev->methods->init_device)
+		return false;
+	return djdev->methods->init_device(djdev);
+}
+
+static inline int call_parse_raw_event(struct dj_device *djdev,
+					struct dj_report *djrep)
+{
+	if (!djdev || !djdev->methods || !djdev->methods->parse_raw_event)
+		return false;
+	return djdev->methods->parse_raw_event(djdev, djrep);
+}
+
+static inline void call_destroy(struct dj_device *djdev)
+{
+	if (!djdev || !djdev->methods || !djdev->methods->destroy)
+		return;
+	djdev->methods->destroy(djdev);
+}
+
+static struct dj_device_method dj_device_method[] = {
+
+	/* last element */
+	{ NULL, }
+};
+
+static inline struct dj_device *logi_djrcv2djdev(
+					struct dj_receiver_dev *djrcv_dev,
+					int index)
+{
+	if ((index < DJ_DEVICE_INDEX_MIN) ||
+	    (index > DJ_DEVICE_INDEX_MAX))
+		return NULL;
+
+	return djrcv_dev->paired_dj_devices[index];
+}
 
 static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
 						struct dj_report *dj_report)
@@ -203,7 +247,11 @@ static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
 	unsigned long flags;
 
 	spin_lock_irqsave(&djrcv_dev->lock, flags);
-	dj_dev = djrcv_dev->paired_dj_devices[dj_report->device_index];
+	dj_dev = logi_djrcv2djdev(djrcv_dev, dj_report->device_index);
+	if (!dj_dev)
+		return;
+	call_destroy(dj_dev);
+
 	djrcv_dev->paired_dj_devices[dj_report->device_index] = NULL;
 	spin_unlock_irqrestore(&djrcv_dev->lock, flags);
 
@@ -216,93 +264,270 @@ static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
 	}
 }
 
-static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
+/*
+ * This function send a request of the device name
+ * see "Logitech hidpp 1.0 excerpt for public release" chapter 4.5.3
+ * for further information.
+ *
+ * The results are read in logi_dj_raw_event()
+ */
+static int logi_send_name_request(struct dj_device *dj_device)
+{
+	struct dj_report *dj_report;
+	int retval;
+
+	dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
+	if (!dj_report)
+		return -ENOMEM;
+
+	dj_report->report_id = REPORT_ID_RECV_SHORT;
+	dj_report->device_index = REPORT_RECEIVER_INDEX;
+	dj_report->report_type = REPORT_GET_LONG_REGISTER_REQ;
+	dj_report->report_params[0] = REPORT_REG_PAIRING_INFORMATION;
+
+	/*
+	 * 0x40 device id 1, 0x41 device id 2....
+	 */
+	dj_report->report_params[1] = 0x40 + dj_device->device_index - 1;
+
+	retval = hid_hw_raw_request(dj_device->dj_receiver_dev->hdev,
+		dj_report->report_id,
+		(void *)dj_report, REPORT_ID_RECV_SHORT_LENGTH,
+		HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
+
+	kfree(dj_report);
+	return retval;
+}
+
+static int logi_dj_recv_create_dj_device(struct dj_receiver_dev *djrcv_dev,
 					  struct dj_report *dj_report)
 {
 	/* Called in delayed work context */
 	struct hid_device *djrcv_hdev = djrcv_dev->hdev;
-	struct usb_interface *intf = to_usb_interface(djrcv_hdev->dev.parent);
-	struct usb_device *usbdev = interface_to_usbdev(intf);
-	struct hid_device *dj_hiddev;
 	struct dj_device *dj_dev;
 
-	/* Device index goes from 1 to 6, we need 3 bytes to store the
-	 * semicolon, the index, and a null terminator
-	 */
-	unsigned char tmpstr[3];
-
 	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;
+		return -EINVAL;
 	}
 
 	if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) ||
 	    (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) {
 		dev_err(&djrcv_hdev->dev, "%s: invalid device index:%d\n",
 			__func__, dj_report->device_index);
-		return;
+		return -EINVAL;
 	}
 
 	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;
+		return -EEXIST;
+	}
+
+	dj_dev = kzalloc(sizeof(struct dj_device), GFP_KERNEL);
+
+	if (!dj_dev) {
+		dev_err(&djrcv_hdev->dev, "%s: failed allocating dj_device\n",
+			__func__);
+		return -ENOMEM;
 	}
 
+	dj_dev->reports_supported = get_unaligned_le32(
+		dj_report->report_params + DEVICE_PAIRED_RF_REPORT_TYPE);
+	dj_dev->dj_receiver_dev = djrcv_dev;
+	dj_dev->device_index = dj_report->device_index;
+	dj_dev->enabled = false;
+
+	dj_dev->wpid =
+		dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_MSB]<<8|
+		dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_LSB];
+
+	djrcv_dev->paired_dj_devices[dj_report->device_index] = dj_dev;
+
+	return 0;
+
+}
+
+/*
+ * this function finalize the device
+ */
+static int logi_dj_recv_add_djhid_device(struct dj_device *dj_device)
+{
+	struct hid_device *dj_hiddev;
+	struct dj_receiver_dev *djrcv_dev;
+
+	struct hid_device *djrcv_hdev;
+	struct usb_interface *intf;
+	struct usb_device *usbdev;
+
+	/* Device index goes from 1 to 6, we need 3 bytes to store the
+	 * semicolon, the index, and a null terminator
+	 */
+	unsigned char tmpstr[3];
+
+	BUG_ON(!dj_device);
+	djrcv_dev = dj_device->dj_receiver_dev;
+	djrcv_hdev = djrcv_dev->hdev;
+
+	/* Called in delayed work context */
+	intf = to_usb_interface(djrcv_hdev->dev.parent);
+	usbdev = interface_to_usbdev(intf);
+
 	dj_hiddev = hid_allocate_device();
 	if (IS_ERR(dj_hiddev)) {
 		dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
 			__func__);
-		return;
+		return -ENOMEM;
 	}
 
 	dj_hiddev->ll_driver = &logi_dj_ll_driver;
-
+	dj_device->hdev = dj_hiddev;
+	dj_hiddev->driver_data = dj_device;
 	dj_hiddev->dev.parent = &djrcv_hdev->dev;
 	dj_hiddev->bus = BUS_USB;
 	dj_hiddev->vendor = le16_to_cpu(usbdev->descriptor.idVendor);
 	dj_hiddev->product = le16_to_cpu(usbdev->descriptor.idProduct);
 	snprintf(dj_hiddev->name, sizeof(dj_hiddev->name),
-		"Logitech Unifying Device. Wireless PID:%02x%02x",
-		dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_MSB],
-		dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_LSB]);
+		"Logitech Unifying Device. Wireless PID:%04x",
+			dj_device->wpid);
 
 	usb_make_path(usbdev, dj_hiddev->phys, sizeof(dj_hiddev->phys));
-	snprintf(tmpstr, sizeof(tmpstr), ":%d", dj_report->device_index);
+	snprintf(tmpstr, sizeof(tmpstr), ":%d", dj_device->device_index);
 	strlcat(dj_hiddev->phys, tmpstr, sizeof(dj_hiddev->phys));
 
-	dj_dev = kzalloc(sizeof(struct dj_device), GFP_KERNEL);
-
-	if (!dj_dev) {
-		dev_err(&djrcv_hdev->dev, "%s: failed allocating dj_device\n",
+	if (hid_add_device(dj_hiddev)) {
+		dev_err(&djrcv_dev->hdev->dev,
+				"%s: failed adding dj_device\n",
 			__func__);
-		goto dj_device_allocate_fail;
+		djrcv_dev->paired_dj_devices[dj_device->device_index] = NULL;
+		kfree(dj_device);
+		hid_destroy_device(dj_hiddev);
+		return -ENODEV;
 	}
 
-	dj_dev->reports_supported = get_unaligned_le32(
-		dj_report->report_params + DEVICE_PAIRED_RF_REPORT_TYPE);
-	dj_dev->hdev = dj_hiddev;
-	dj_dev->dj_receiver_dev = djrcv_dev;
-	dj_dev->device_index = dj_report->device_index;
-	dj_hiddev->driver_data = dj_dev;
+	hid_info(djrcv_dev->hdev, "Device %d: '%s' added\n",
+		dj_device->device_index, dj_device->device_name);
 
-	djrcv_dev->paired_dj_devices[dj_report->device_index] = dj_dev;
+	return 0;
+}
 
-	if (hid_add_device(dj_hiddev)) {
-		dev_err(&djrcv_hdev->dev, "%s: failed adding dj_device\n",
-			__func__);
-		goto hid_add_device_fail;
+static void logi_set_device_name(struct dj_device *dj_device,
+				 struct dj_report *dj_report)
+{
+
+	struct dj_device_method	*m;
+	struct dj_receiver_dev *djrcv_dev = dj_device->dj_receiver_dev;
+
+	strlcpy(dj_device->device_name, dj_report->report_params+3,
+		sizeof(dj_device->device_name));
+
+	hid_info(djrcv_dev->hdev, "Device %d: '%s'\n",
+		dj_device->device_index,
+		dj_device->device_name);
+
+	for (m = dj_device_method ; m->device_names ; m++) {
+		char **name;
+
+		for (name = m->device_names ; name ; name++) {
+			if (!strcmp(*name, dj_device->device_name)) {
+				dj_device->methods = m;
+				hid_info(djrcv_dev->hdev,
+					"Found methods for device '%s'\n",
+					dj_device->device_name);
+				return;
+			}
+		}
 	}
 
-	return;
+}
+
+/*
+ * finalize the dj_device creation, because now we know the driver name
+ */
+static inline cvoid __dj_device_init_2(struct dj_receiver_dev *djrcv_dev,
+				struct dj_report *dj_report)
+{
+	int dev_index = dj_report->report_params[1]-0x40+1;
+	struct dj_device *dj_device = logi_djrcv2djdev(djrcv_dev, dev_index);
+	int retval;
 
-hid_add_device_fail:
-	djrcv_dev->paired_dj_devices[dj_report->device_index] = NULL;
-	kfree(dj_dev);
-dj_device_allocate_fail:
-	hid_destroy_device(dj_hiddev);
+	if (!dj_device) {
+		dbg_hid("%s: cannot find %d device\n",
+			__func__, dev_index);
+		/* do rescan */
+		retval = logi_dj_recv_query_paired_devices(djrcv_dev);
+		if (!retval)
+			dev_err(&djrcv_dev->hdev->dev,
+			  "%s:logi_dj_recv_query_paired_devices error:%d\n",
+			  __func__, retval);
+
+		return;
+	}
+
+	if (dj_device->enabled) {
+		dbg_hid("%s: device %d already initializated\n",
+			__func__, dev_index);
+		return;
+	}
+
+	logi_set_device_name(dj_device, dj_report);
+
+	if (logi_dj_recv_add_djhid_device(dj_device) < 0) {
+		logi_dj_recv_destroy_djhid_device(djrcv_dev, dj_report);
+		dev_err(&djrcv_dev->hdev->dev,
+			"Cannot create the hid device\n");
+		return;
+	}
+	if (call_init_device(dj_device)) {
+		logi_dj_recv_destroy_djhid_device(djrcv_dev, dj_report);
+		dev_err(&djrcv_dev->hdev->dev,
+			"Cannot init the hid device\n");
+		return;
+	}
+
+	barrier();
+	dj_device->enabled = true;
+}
+
+/*
+ * Initialize the dj_device structure, but a) doesn't enable it, and b)
+ * doesn't crete the hid device, because we don't now the driver.
+ */
+static inline void __dj_device_init_1(struct dj_receiver_dev *djrcv_dev,
+				struct dj_report *dj_report)
+{
+	int dev_index;
+	struct dj_device *dj_device;
+	int ret;
+
+	dev_index = dj_report->device_index;
+	dj_device = logi_djrcv2djdev(djrcv_dev, dev_index);
+	if (dj_device) {
+		dev_warn(&djrcv_dev->hdev->dev,
+			"This device (%d) already exist\n", dev_index);
+		return;
+	}
+
+	ret = logi_dj_recv_create_dj_device(djrcv_dev, dj_report);
+	if (ret == -EINVAL) {
+		/* This report is not valid, ignore it */
+		return;
+	}
+	if (ret < 0) {
+		dev_err(&djrcv_dev->hdev->dev,
+			"Cannot allocate the hid device %d.%d\n",
+			dj_report->device_index, dj_report->report_type);
+		return;
+	}
+	/* we have to re-taken it, because before was not created */
+	dj_device = logi_djrcv2djdev(djrcv_dev, dev_index);
+	if (logi_send_name_request(dj_device) < 0) {
+		logi_dj_recv_destroy_djhid_device(djrcv_dev, dj_report);
+		dev_err(&djrcv_dev->hdev->dev,
+			"Cannot query the device name\n");
+	}
 }
 
 static void delayedwork_callback(struct work_struct *work)
@@ -314,6 +539,8 @@ static void delayedwork_callback(struct work_struct *work)
 	unsigned long flags;
 	int count;
 	int retval;
+	int	dev_index;
+	struct dj_device *dj_device;
 
 	dbg_hid("%s\n", __func__);
 
@@ -339,9 +566,14 @@ static void delayedwork_callback(struct work_struct *work)
 	spin_unlock_irqrestore(&djrcv_dev->lock, flags);
 
 	switch (dj_report.report_type) {
+	case REPORT_GET_LONG_REGISTER_REQ:
+		__dj_device_init_2(djrcv_dev, &dj_report);
+		break;
+
 	case REPORT_TYPE_NOTIF_DEVICE_PAIRED:
-		logi_dj_recv_add_djhid_device(djrcv_dev, &dj_report);
+		__dj_device_init_1(djrcv_dev, &dj_report);
 		break;
+
 	case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED:
 		logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report);
 		break;
@@ -353,20 +585,23 @@ static void delayedwork_callback(struct work_struct *work)
 	 * 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__);
+		dev_index = dj_report.device_index;
+		dj_device = logi_djrcv2djdev(djrcv_dev, dev_index);
+		if (!dj_device) {
+			/* 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__);
 	}
+
 }
 
 static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev,
@@ -390,7 +625,7 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
 	u8 reportbuffer[MAX_REPORT_SIZE];
 	struct dj_device *djdev;
 
-	djdev = djrcv_dev->paired_dj_devices[dj_report->device_index];
+	djdev = logi_djrcv2djdev(djrcv_dev, dj_report->device_index);
 
 	if (!djdev) {
 		dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
@@ -404,6 +639,10 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
 		return;
 	}
 
+	/* device not enabled */
+	if (!djdev->enabled)
+		return;
+
 	memset(reportbuffer, 0, sizeof(reportbuffer));
 
 	for (i = 0; i < NUMBER_OF_HID_REPORTS; i++) {
@@ -440,6 +679,10 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
 		return;
 	}
 
+	/* device not enabled */
+	if (!dj_device->enabled)
+		return;
+
 	if ((dj_report->report_type > ARRAY_SIZE(hid_reportid_size_map) - 1) ||
 	    (hid_reportid_size_map[dj_report->report_type] == 0)) {
 		dbg_hid("invalid report type:%x\n", dj_report->report_type);
@@ -451,8 +694,8 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
 			hid_reportid_size_map[dj_report->report_type], 1)) {
 		dbg_hid("hid_input_report error\n");
 	}
-}
 
+}
 
 static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
 				    struct dj_report *dj_report)
@@ -584,6 +827,10 @@ static int logi_dj_ll_parse(struct hid_device *hid)
 	char *rdesc;
 	int retval;
 
+	/* try the specific hook */
+	if (djdev->methods && djdev->methods->parse)
+		return djdev->methods->parse(djdev);
+
 	dbg_hid("%s\n", __func__);
 
 	djdev->hdev->version = 0x0111;
@@ -655,7 +902,6 @@ static struct hid_ll_driver logi_dj_ll_driver = {
 	.raw_request = logi_dj_ll_raw_request,
 };
 
-
 static int logi_dj_raw_event(struct hid_device *hdev,
 			     struct hid_report *report, u8 *data,
 			     int size)
@@ -692,25 +938,51 @@ static int logi_dj_raw_event(struct hid_device *hdev,
 	 */
 
 	spin_lock_irqsave(&djrcv_dev->lock, flags);
-	if (dj_report->report_id == REPORT_ID_DJ_SHORT) {
-		switch (dj_report->report_type) {
-		case REPORT_TYPE_NOTIF_DEVICE_PAIRED:
-		case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED:
-			logi_dj_recv_queue_notification(djrcv_dev, dj_report);
-			break;
-		case REPORT_TYPE_NOTIF_CONNECTION_STATUS:
-			if (dj_report->report_params[CONNECTION_STATUS_PARAM_STATUS] ==
-			    STATUS_LINKLOSS) {
-				logi_dj_recv_forward_null_report(djrcv_dev, dj_report);
-			}
-			break;
-		default:
-			logi_dj_recv_forward_report(djrcv_dev, dj_report);
+
+	if (dj_report->report_id == REPORT_ID_RECV_LONG &&
+	    dj_report->device_index == REPORT_RECEIVER_INDEX &&
+	    dj_report->report_type == REPORT_GET_LONG_REGISTER_REQ &&
+	    dj_report->report_params[0] == REPORT_REG_PAIRING_INFORMATION &&
+	    dj_report->report_params[1] >= REPORT_REG2_NOTIFY_DEVICE_NAME &&
+	    dj_report->report_params[1] < (REPORT_REG2_NOTIFY_DEVICE_NAME+
+						DJ_DEVICE_INDEX_COUNT)) {
+
+		logi_dj_recv_queue_notification(djrcv_dev, dj_report);
+		report_processed = true;
+	} else if (dj_report->report_id == REPORT_ID_DJ_SHORT &&
+		   (dj_report->report_type ==
+			REPORT_TYPE_NOTIF_DEVICE_PAIRED ||
+		    dj_report->report_type ==
+			REPORT_TYPE_NOTIF_DEVICE_UNPAIRED)) {
+
+		logi_dj_recv_queue_notification(djrcv_dev, dj_report);
+		report_processed = true;
+	} else if (dj_report->report_id == REPORT_ID_DJ_SHORT &&
+		   dj_report->report_type ==
+			REPORT_TYPE_NOTIF_CONNECTION_STATUS) {
+
+		if (dj_report->report_params[CONNECTION_STATUS_PARAM_STATUS] ==
+				STATUS_LINKLOSS) {
+
+			logi_dj_recv_forward_null_report(djrcv_dev, dj_report);
 		}
 		report_processed = true;
+	} else {
+		bool skip = false;
+		struct dj_device *djdev;
+
+		djdev = logi_djrcv2djdev(djrcv_dev, dj_report->device_index);
+		if (djdev && djdev->enabled) {
+			skip = call_parse_raw_event(djdev, dj_report);
+			report_processed = skip;
+		}
+		if (!skip && dj_report->report_id == REPORT_ID_DJ_SHORT) {
+			logi_dj_recv_forward_report(djrcv_dev, dj_report);
+			report_processed = true;
+		}
 	}
-	spin_unlock_irqrestore(&djrcv_dev->lock, flags);
 
+	spin_unlock_irqrestore(&djrcv_dev->lock, flags);
 	return report_processed;
 }
 
@@ -865,12 +1137,12 @@ static void logi_dj_remove(struct hid_device *hdev)
 	for (i = 0; i < (DJ_MAX_PAIRED_DEVICES + DJ_DEVICE_INDEX_MIN); i++) {
 		dj_dev = djrcv_dev->paired_dj_devices[i];
 		if (dj_dev != NULL) {
-			hid_destroy_device(dj_dev->hdev);
+			if (dj_dev->hdev)
+				hid_destroy_device(dj_dev->hdev);
 			kfree(dj_dev);
 			djrcv_dev->paired_dj_devices[i] = NULL;
 		}
 	}
-
 	kfifo_free(&djrcv_dev->notif_fifo);
 	kfree(djrcv_dev);
 	hid_set_drvdata(hdev, NULL);
diff --git a/drivers/hid/hid-logitech-dj.h b/drivers/hid/hid-logitech-dj.h
index 4a40003..d81ed7d 100644
--- a/drivers/hid/hid-logitech-dj.h
+++ b/drivers/hid/hid-logitech-dj.h
@@ -29,12 +29,17 @@
 #define DJ_MAX_NUMBER_NOTIFICATIONS		8
 #define DJ_DEVICE_INDEX_MIN 			1
 #define DJ_DEVICE_INDEX_MAX 			6
+#define DJ_DEVICE_INDEX_COUNT			(DJ_DEVICE_INDEX_MAX - \
+						 DJ_DEVICE_INDEX_MIN+1)
 
 #define DJREPORT_SHORT_LENGTH			15
 #define DJREPORT_LONG_LENGTH			32
+#define REPORT_ID_RECV_SHORT_LENGTH		7
 
 #define REPORT_ID_DJ_SHORT			0x20
 #define REPORT_ID_DJ_LONG			0x21
+#define REPORT_ID_RECV_SHORT			0x10
+#define REPORT_ID_RECV_LONG			0x11
 
 #define REPORT_TYPE_RFREPORT_FIRST		0x01
 #define REPORT_TYPE_RFREPORT_LAST		0x1F
@@ -60,6 +65,10 @@
 /* Device Un-Paired Notification */
 #define REPORT_TYPE_NOTIF_DEVICE_UNPAIRED	0x40
 
+/* Device "Unifying Device name" Notification */
+#define REPORT_GET_LONG_REGISTER_REQ		0x83
+#define REPORT_REG_PAIRING_INFORMATION		0xb5
+#define REPORT_REG2_NOTIFY_DEVICE_NAME		0x40
 
 /* Connection Status Notification */
 #define REPORT_TYPE_NOTIF_CONNECTION_STATUS	0x42
@@ -79,6 +88,9 @@
 #define REPORT_TYPE_MEDIA_CENTER		0x08
 #define REPORT_TYPE_LEDS			0x0E
 
+/* receiver device index */
+#define REPORT_RECEIVER_INDEX			0xff
+
 /* RF Report types bitfield */
 #define STD_KEYBOARD				0x00000002
 #define STD_MOUSE				0x00000004
@@ -104,11 +116,40 @@ struct dj_receiver_dev {
 	bool querying_devices;
 };
 
+struct dj_device;
+
+/**
+ * these methods are invoked instead the default ones
+ * @devices_name		array of device name supported by this driver
+ * @init_device			init method for the device. If the returned
+ *				value is 0, the device was initiated correctly.
+ *				Otherwise the device is not created.
+ * @parse_raw_event		this method is called when a raw event arrived
+ *				it permits to change the event.
+ *				If the value returned is not zero the standard
+ *				handler is called after.
+ * @parse			this method allow to generate and pass a
+ *				device descriptor to the higher level.
+ * @destroy			called when the device has to be deleted
+ */
+struct dj_device_method {
+	char **device_names;
+	int (*init_device)(struct dj_device *);
+	int (*parse_raw_event)(struct dj_device *, struct dj_report *);
+	int (*parse)(struct dj_device *);
+	void (*destroy)(struct dj_device *);
+};
+
 struct dj_device {
 	struct hid_device *hdev;
 	struct dj_receiver_dev *dj_receiver_dev;
 	u32 reports_supported;
 	u8 device_index;
+	int  enabled;
+	char device_name[16];
+	u16 wpid;
+	struct dj_device_method *methods;
+	void *userdata;
 };
 
 /**
-- 
1.9.3

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux