linux/drivers/hid/hid-logitech-dj.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 *  HID driver for Logitech receivers
 *
 *  Copyright (c) 2011 Logitech
 */



#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/kfifo.h>
#include <linux/delay.h>
#include <linux/usb.h> /* For to_usb_interface for kvm extra intf check */
#include <asm/unaligned.h>
#include "hid-ids.h"

#define DJ_MAX_PAIRED_DEVICES
#define DJ_MAX_NUMBER_NOTIFS
#define DJ_RECEIVER_INDEX
#define DJ_DEVICE_INDEX_MIN
#define DJ_DEVICE_INDEX_MAX

#define DJREPORT_SHORT_LENGTH
#define DJREPORT_LONG_LENGTH

#define REPORT_ID_DJ_SHORT
#define REPORT_ID_DJ_LONG

#define REPORT_ID_HIDPP_SHORT
#define REPORT_ID_HIDPP_LONG
#define REPORT_ID_HIDPP_VERY_LONG

#define HIDPP_REPORT_SHORT_LENGTH
#define HIDPP_REPORT_LONG_LENGTH

#define HIDPP_RECEIVER_INDEX

#define REPORT_TYPE_RFREPORT_FIRST
#define REPORT_TYPE_RFREPORT_LAST

/* Command Switch to DJ mode */
#define REPORT_TYPE_CMD_SWITCH
#define CMD_SWITCH_PARAM_DEVBITFIELD
#define CMD_SWITCH_PARAM_TIMEOUT_SECONDS
#define TIMEOUT_NO_KEEPALIVE

/* Command to Get the list of Paired devices */
#define REPORT_TYPE_CMD_GET_PAIRED_DEVICES

/* Device Paired Notification */
#define REPORT_TYPE_NOTIF_DEVICE_PAIRED
#define SPFUNCTION_MORE_NOTIF_EXPECTED
#define SPFUNCTION_DEVICE_LIST_EMPTY
#define DEVICE_PAIRED_PARAM_SPFUNCTION
#define DEVICE_PAIRED_PARAM_EQUAD_ID_LSB
#define DEVICE_PAIRED_PARAM_EQUAD_ID_MSB
#define DEVICE_PAIRED_RF_REPORT_TYPE

/* Device Un-Paired Notification */
#define REPORT_TYPE_NOTIF_DEVICE_UNPAIRED

/* Connection Status Notification */
#define REPORT_TYPE_NOTIF_CONNECTION_STATUS
#define CONNECTION_STATUS_PARAM_STATUS
#define STATUS_LINKLOSS

/* Error Notification */
#define REPORT_TYPE_NOTIF_ERROR
#define NOTIF_ERROR_PARAM_ETYPE
#define ETYPE_KEEPALIVE_TIMEOUT

/* supported DJ HID && RF report types */
#define REPORT_TYPE_KEYBOARD
#define REPORT_TYPE_MOUSE
#define REPORT_TYPE_CONSUMER_CONTROL
#define REPORT_TYPE_SYSTEM_CONTROL
#define REPORT_TYPE_MEDIA_CENTER
#define REPORT_TYPE_LEDS

/* RF Report types bitfield */
#define STD_KEYBOARD
#define STD_MOUSE
#define MULTIMEDIA
#define POWER_KEYS
#define KBD_MOUSE
#define MEDIA_CENTER
#define KBD_LEDS
/* Fake (bitnr > NUMBER_OF_HID_REPORTS) bit to track HID++ capability */
#define HIDPP

/* HID++ Device Connected Notification */
#define REPORT_TYPE_NOTIF_DEVICE_CONNECTED
#define HIDPP_PARAM_PROTO_TYPE
#define HIDPP_PARAM_DEVICE_INFO
#define HIDPP_PARAM_EQUAD_LSB
#define HIDPP_PARAM_EQUAD_MSB
#define HIDPP_PARAM_27MHZ_DEVID
#define HIDPP_DEVICE_TYPE_MASK
#define HIDPP_LINK_STATUS_MASK
#define HIDPP_MANUFACTURER_MASK
#define HIDPP_27MHZ_SECURE_MASK

#define HIDPP_DEVICE_TYPE_KEYBOARD
#define HIDPP_DEVICE_TYPE_MOUSE

#define HIDPP_SET_REGISTER
#define HIDPP_GET_LONG_REGISTER
#define HIDPP_REG_CONNECTION_STATE
#define HIDPP_REG_PAIRING_INFORMATION
#define HIDPP_PAIRING_INFORMATION
#define HIDPP_FAKE_DEVICE_ARRIVAL

enum recvr_type {};

struct dj_report {};

struct hidpp_event {} __packed;

struct dj_receiver_dev {};

struct dj_device {};

#define WORKITEM_TYPE_EMPTY
#define WORKITEM_TYPE_PAIRED
#define WORKITEM_TYPE_UNPAIRED
#define WORKITEM_TYPE_UNKNOWN

struct dj_workitem {};

/* Keyboard descriptor (1) */
static const char kbd_descriptor[] =;

/* Mouse descriptor (2)     */
static const char mse_descriptor[] =;

/* Mouse descriptor (2) for 27 MHz receiver, only 8 buttons */
static const char mse_27mhz_descriptor[] =;

/* Mouse descriptor (2) for Bluetooth receiver, low-res hwheel, 12 buttons */
static const char mse_bluetooth_descriptor[] =;

/* Mouse descriptor (5) for Bluetooth receiver, normal-res hwheel, 8 buttons */
static const char mse5_bluetooth_descriptor[] =;

/* Gaming Mouse descriptor (2) */
static const char mse_high_res_descriptor[] =;

/* Consumer Control descriptor (3) */
static const char consumer_descriptor[] =;				/*                                     */

/* System control descriptor (4) */
static const char syscontrol_descriptor[] =;

/* Media descriptor (8) */
static const char media_descriptor[] =;				/*                                     */

/* HIDPP descriptor */
static const char hidpp_descriptor[] =;

/* Maximum size of all defined hid reports in bytes (including report id) */
#define MAX_REPORT_SIZE

/* Make sure all descriptors are present here */
#define MAX_RDESC_SIZE

/* Number of possible hid report types that can be created by this driver.
 *
 * Right now, RF report types have the same report types (or report id's)
 * than the hid report created from those RF reports. In the future
 * this doesnt have to be true.
 *
 * For instance, RF report type 0x01 which has a size of 8 bytes, corresponds
 * to hid report id 0x01, this is standard keyboard. Same thing applies to mice
 * reports and consumer control, etc. If a new RF report is created, it doesn't
 * has to have the same report id as its corresponding hid report, so an
 * translation may have to take place for future report types.
 */
#define NUMBER_OF_HID_REPORTS
static const u8 hid_reportid_size_map[NUMBER_OF_HID_REPORTS] =;


#define LOGITECH_DJ_INTERFACE_NUMBER

static const struct hid_ll_driver logi_dj_ll_driver;

static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
static void delayedwork_callback(struct work_struct *work);

static LIST_HEAD(dj_hdev_list);
static DEFINE_MUTEX(dj_hdev_list_lock);

static bool recvr_type_is_bluetooth(enum recvr_type type)
{}

/*
 * dj/HID++ receivers are really a single logical entity, but for BIOS/Windows
 * compatibility they have multiple USB interfaces. On HID++ receivers we need
 * to listen for input reports on both interfaces. The functions below are used
 * to create a single struct dj_receiver_dev for all interfaces belonging to
 * a single USB-device / receiver.
 */
static struct dj_receiver_dev *dj_find_receiver_dev(struct hid_device *hdev,
						    enum recvr_type type)
{}

static void dj_release_receiver_dev(struct kref *kref)
{}

static void dj_put_receiver_dev(struct hid_device *hdev)
{}

static struct dj_receiver_dev *dj_get_receiver_dev(struct hid_device *hdev,
						   enum recvr_type type,
						   unsigned int application,
						   bool is_hidpp)
{}

static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
					      struct dj_workitem *workitem)
{}

static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
					  struct dj_workitem *workitem)
{}

static void delayedwork_callback(struct work_struct *work)
{}

/*
 * Sometimes we receive reports for which we do not have a paired dj_device
 * associated with the device_index or report-type to forward the report to.
 * This means that the original "device paired" notification corresponding
 * to the dj_device never arrived to this driver. Possible reasons for this are:
 * 1) hid-core discards all packets coming from a device during probe().
 * 2) if the receiver is plugged into a KVM switch then the pairing reports
 * are only forwarded to it if the focus is on this PC.
 * This function deals with this by re-asking the receiver for the list of
 * connected devices in the delayed work callback.
 * This function MUST be called with djrcv->lock held.
 */
static void logi_dj_recv_queue_unknown_work(struct dj_receiver_dev *djrcv_dev)
{}

static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev,
					   struct dj_report *dj_report)
{}

/*
 * Some quad/bluetooth keyboards have a builtin touchpad in this case we see
 * only 1 paired device with a device_type of REPORT_TYPE_KEYBOARD. For the
 * touchpad to work we must also forward mouse input reports to the dj_hiddev
 * created for the keyboard (instead of forwarding them to a second paired
 * device with a device_type of REPORT_TYPE_MOUSE as we normally would).
 *
 * On Dinovo receivers the keyboard's touchpad and an optional paired actual
 * mouse send separate input reports, INPUT(2) aka STD_MOUSE for the mouse
 * and INPUT(5) aka KBD_MOUSE for the keyboard's touchpad.
 *
 * On MX5x00 receivers (which can also be paired with a Dinovo keyboard)
 * INPUT(2) is used for both an optional paired actual mouse and for the
 * keyboard's touchpad.
 */
static const u16 kbd_builtin_touchpad_ids[] =;

static void logi_hidpp_dev_conn_notif_equad(struct hid_device *hdev,
					    struct hidpp_event *hidpp_report,
					    struct dj_workitem *workitem)
{}

static void logi_hidpp_dev_conn_notif_27mhz(struct hid_device *hdev,
					    struct hidpp_event *hidpp_report,
					    struct dj_workitem *workitem)
{}

static void logi_hidpp_recv_queue_notif(struct hid_device *hdev,
					struct hidpp_event *hidpp_report)
{}

static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
					     struct dj_report *dj_report)
{}

static void logi_dj_recv_forward_dj(struct dj_receiver_dev *djrcv_dev,
				    struct dj_report *dj_report)
{}

static void logi_dj_recv_forward_report(struct dj_device *dj_dev, u8 *data,
					int size)
{}

static void logi_dj_recv_forward_input_report(struct hid_device *hdev,
					      u8 *data, int size)
{}

static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
				    struct dj_report *dj_report)
{}

static int logi_dj_recv_query_hidpp_devices(struct dj_receiver_dev *djrcv_dev)
{}

static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
{}


static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
					  unsigned timeout)
{}


static int logi_dj_ll_open(struct hid_device *hid)
{}

static void logi_dj_ll_close(struct hid_device *hid)
{}

/*
 * Register 0xB5 is "pairing information". It is solely intended for the
 * receiver, so do not overwrite the device index.
 */
static u8 unifying_pairing_query[]  =;
static u8 unifying_pairing_answer[] =;

static int logi_dj_ll_raw_request(struct hid_device *hid,
				  unsigned char reportnum, __u8 *buf,
				  size_t count, unsigned char report_type,
				  int reqtype)
{}

static void rdcat(char *rdesc, unsigned int *rsize, const char *data, unsigned int size)
{}

static int logi_dj_ll_parse(struct hid_device *hid)
{}

static int logi_dj_ll_start(struct hid_device *hid)
{}

static void logi_dj_ll_stop(struct hid_device *hid)
{}

static bool logi_dj_ll_may_wakeup(struct hid_device *hid)
{}

static const struct hid_ll_driver logi_dj_ll_driver =;

static int logi_dj_dj_event(struct hid_device *hdev,
			     struct hid_report *report, u8 *data,
			     int size)
{}

static int logi_dj_hidpp_event(struct hid_device *hdev,
			     struct hid_report *report, u8 *data,
			     int size)
{}

static int logi_dj_raw_event(struct hid_device *hdev,
			     struct hid_report *report, u8 *data,
			     int size)
{}

static int logi_dj_probe(struct hid_device *hdev,
			 const struct hid_device_id *id)
{}

#ifdef CONFIG_PM
static int logi_dj_reset_resume(struct hid_device *hdev)
{}
#endif

static void logi_dj_remove(struct hid_device *hdev)
{}

static const struct hid_device_id logi_dj_receivers[] =;

MODULE_DEVICE_TABLE(hid, logi_dj_receivers);

static struct hid_driver logi_djreceiver_driver =;

module_hid_driver();

MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_AUTHOR();