Пример #1
0
static int zpff_init(struct hid_device *hid)
{
	struct zpff_device *zpff;
	struct hid_report *report;
	struct hid_input *hidinput = list_entry(hid->inputs.next,
						struct hid_input, list);
	struct list_head *report_list =
			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
	struct input_dev *dev = hidinput->input;
	int error;

	if (list_empty(report_list)) {
		hid_err(hid, "no output report found\n");
		return -ENODEV;
	}

	report = list_entry(report_list->next, struct hid_report, list);

	if (report->maxfield < 4) {
		hid_err(hid, "not enough fields in report\n");
		return -ENODEV;
	}

	zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL);
	if (!zpff)
		return -ENOMEM;

	set_bit(FF_RUMBLE, dev->ffbit);

	error = input_ff_create_memless(dev, zpff, zpff_play);
	if (error) {
		kfree(zpff);
		return error;
	}

	zpff->report = report;
	zpff->report->field[0]->value[0] = 0x00;
	zpff->report->field[1]->value[0] = 0x02;
	zpff->report->field[2]->value[0] = 0x00;
	zpff->report->field[3]->value[0] = 0x00;
	hid_hw_request(hid, zpff->report, HID_REQ_SET_REPORT);

	hid_info(hid, "force feedback for Zeroplus based devices by Anssi Hannula <*****@*****.**>\n");

	return 0;
}
Пример #2
0
static int axff_init(struct hid_device *hid)
{
	struct axff_device *axff;
	struct hid_report *report;
	struct hid_input *hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
	struct list_head *report_list =&hid->report_enum[HID_OUTPUT_REPORT].report_list;
	struct input_dev *dev = hidinput->input;
	int error;

	if (list_empty(report_list)) {
		hid_err(hid, "no output reports found\n");
		return -ENODEV;
	}

	report = list_first_entry(report_list, struct hid_report, list);

	if (report->maxfield < 4) {
		hid_err(hid, "no fields in the report: %d\n", report->maxfield);
		return -ENODEV;
	}

	axff = kzalloc(sizeof(struct axff_device), GFP_KERNEL);
	if (!axff)
		return -ENOMEM;

	set_bit(FF_RUMBLE, dev->ffbit);

	error = input_ff_create_memless(dev, axff, axff_play);
	if (error)
		goto err_free_mem;

	axff->report = report;
	axff->report->field[0]->value[0] = 0x00;
	axff->report->field[1]->value[0] = 0x00;
	axff->report->field[2]->value[0] = 0x00;
	axff->report->field[3]->value[0] = 0x00;
	usbhid_submit_report(hid, axff->report, USB_DIR_OUT);

	hid_info(hid, "Force Feedback for ACRUX game controllers by Sergei Kolzun<*****@*****.**>\n");

	return 0;

err_free_mem:
	kfree(axff);
	return error;
}
Пример #3
0
static __u8 *acer_kbd_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize){

  /* Check that the descriptor size matches what we expect */
  if (*rsize == ACER_KBD_RDESC_SIZE) {
    __u64 check = be64_to_cpu(*(__be64 *)(rdesc + ACER_KBD_RDESC_CHECK_POS));
    
    /* check for invalid max usages */
    if (check == ACER_KBD_RDESC_CHECK_DATA) {
      hid_info(hdev, "fixing up acer keyboard report descriptor\n");
      
      /* change max values to 0xFF00 */
      rdesc[ACER_KBD_RDESC_FIX_POS1] = 0x00;
      rdesc[ACER_KBD_RDESC_FIX_POS2] = 0x00;
    }
  }
  
  return rdesc;
}
Пример #4
0
static __u8 *kye_consumer_control_fixup(struct hid_device *hdev, __u8 *rdesc,
		unsigned int *rsize, int offset, const char *device_name) {
	/*
	 * the fixup that need to be done:
	 *   - change Usage Maximum in the Comsumer Control
	 *     (report ID 3) to a reasonable value
	 */
	if (*rsize >= offset + 31 &&
	    /* Usage Page (Consumer Devices) */
	    rdesc[offset] == 0x05 && rdesc[offset + 1] == 0x0c &&
	    /* Usage (Consumer Control) */
	    rdesc[offset + 2] == 0x09 && rdesc[offset + 3] == 0x01 &&
	    /*   Usage Maximum > 12287 */
	    rdesc[offset + 10] == 0x2a && rdesc[offset + 12] > 0x2f) {
		hid_info(hdev, "fixing up %s report descriptor\n", device_name);
		rdesc[offset + 12] = 0x2f;
	}
	return rdesc;
}
Пример #5
0
static void sixaxis_set_led_bt(struct hid_device *hdev)
{
	/* set first LED on BT connection */
	unsigned char led_data[] = {
			0x01,
			/* rumble values */
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			/* LED settings 0x02=LED1 .. 0x10=LED4 */
			0x02,
			0xff, 0x27, 0x10, 0x00, 0x32,	/* LED 4 */
			0xff, 0x27, 0x10, 0x00, 0x32,	/* LED 3 */
			0xff, 0x27, 0x10, 0x00, 0x32,	/* LED 2 */
			0xff, 0x27, 0x10, 0x00, 0x32,	/* LED 1 */
			0x00, 0x00, 0x00, 0x00, 0x00
		};
	hid_info(hdev, "set LED BT\n");
	hdev->hid_output_raw_report(hdev, led_data, sizeof(led_data),
					HID_OUTPUT_REPORT);
}
Пример #6
0
static __u8 *acer_kbd_report_fixup(struct hid_device *hdev, __u8 *rdesc,
		unsigned int *rsize)
{
	/* check for invalid descriptor */
	if (*rsize == ACER_KBD_RDESC_ORIG_SIZE) {
		__u64 check = be64_to_cpu(*(__be64 *)(rdesc + ACER_KBD_RDESC_CHECK_POS));

		/* check for invalid max usages and logical 0xFFFF (2^16) */
		if (check == ACER_KBD_RDESC_CHECK_DATA) {
			hid_info(hdev, "fixing up acer keybaord report descriptor\n");

			/* fix max values with 0xFF00 (2^8) */
			rdesc[ACER_KBD_RDESC_FIX_POS1] = 0x00;
			rdesc[ACER_KBD_RDESC_FIX_POS2] = 0x00;
		}
	}

	return rdesc;
}
Пример #7
0
static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
		unsigned int *rsize)
{
	switch (hdev->product) {
	case USB_DEVICE_ID_KYE_ERGO_525V:
		if (*rsize >= 74 &&
			rdesc[61] == 0x05 && rdesc[62] == 0x08 &&
			rdesc[63] == 0x19 && rdesc[64] == 0x08 &&
			rdesc[65] == 0x29 && rdesc[66] == 0x0f &&
			rdesc[71] == 0x75 && rdesc[72] == 0x08 &&
			rdesc[73] == 0x95 && rdesc[74] == 0x01) {
			hid_info(hdev,
				 "fixing up Kye/Genius Ergo Mouse "
				 "report descriptor\n");
			rdesc[62] = 0x09;
			rdesc[64] = 0x04;
			rdesc[66] = 0x07;
			rdesc[72] = 0x01;
			rdesc[74] = 0x08;
		}
		break;
	case USB_DEVICE_ID_KYE_EASYPEN_I405X:
		if (*rsize == EASYPEN_I405X_RDESC_ORIG_SIZE) {
			rdesc = easypen_i405x_rdesc_fixed;
			*rsize = sizeof(easypen_i405x_rdesc_fixed);
		}
		break;
	case USB_DEVICE_ID_KYE_MOUSEPEN_I608X:
		if (*rsize == MOUSEPEN_I608X_RDESC_ORIG_SIZE) {
			rdesc = mousepen_i608x_rdesc_fixed;
			*rsize = sizeof(mousepen_i608x_rdesc_fixed);
		}
		break;
	case USB_DEVICE_ID_KYE_EASYPEN_M610X:
		if (*rsize == EASYPEN_M610X_RDESC_ORIG_SIZE) {
			rdesc = easypen_m610x_rdesc_fixed;
			*rsize = sizeof(easypen_m610x_rdesc_fixed);
		}
		break;
	}
	return rdesc;
}
/*
 * Microsoft Wireless Desktop Receiver (Model 1028) has
 * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
 */
static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
		unsigned int *rsize)
{
	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);

	if ((quirks & MS_RDESC) && *rsize == 571 && rdesc[557] == 0x19 &&
			rdesc[559] == 0x29) {
		hid_info(hdev, "fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n");
		rdesc[557] = 0x35;
		rdesc[559] = 0x45;
	}
 	/* the same as above (s/usage/physical/) */
	if ((quirks & MS_RDESC_3K) && *rsize == 106 && rdesc[94] == 0x19 &&
			rdesc[95] == 0x00 && rdesc[96] == 0x29 &&
			rdesc[97] == 0xff) {
 		rdesc[94] = 0x35;
 		rdesc[96] = 0x45;
 	}
	return rdesc;
}
Пример #9
0
static __u8 *saitek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
		unsigned int *rsize)
{
	if (*rsize == 137 && rdesc[20] == 0x09 && rdesc[21] == 0x33
			&& rdesc[94] == 0x81 && rdesc[95] == 0x03
			&& rdesc[110] == 0x81 && rdesc[111] == 0x03) {

		hid_info(hdev, "Fixing up Saitek PS1000 report descriptor\n");

		/* convert spurious axis to a "noop" Logical Minimum (0) */
		rdesc[20] = 0x15;
		rdesc[21] = 0x00;

		/* clear constant bit on buttons and d-pad */
		rdesc[95] = 0x02;
		rdesc[111] = 0x02;

	}
	return rdesc;
}
Пример #10
0
static int px_raw_event(struct hid_device *hid, struct hid_report *report,
	 u8 *data, int size)
{
	int idx = size;

	switch (report->id) {
	case 0:		/* keyboard input */
		/*
		 * Convert in-band modifier key values into out of band
		 * modifier bits and pull the key strokes from the report.
		 * Thus a report data set which looked like:
		 *
		 * [00][00][E0][30][00][00][00][00]
		 * (no modifier bits + "Left Shift" key + "1" key)
		 *
		 * Would be converted to:
		 *
		 * [01][00][00][30][00][00][00][00]
		 * (Left Shift modifier bit + "1" key)
		 *
		 * As long as it's in the size range, the upper level
		 * drivers don't particularly care if there are in-band
		 * 0-valued keys, so they don't stop parsing.
		 */
		while (--idx > 1) {
			if (data[idx] < 0xE0 || data[idx] > 0xE7)
				continue;
			data[0] |= (1 << (data[idx] - 0xE0));
			data[idx] = 0;
		}
		hid_report_raw_event(hid, HID_INPUT_REPORT, data, size, 0);
		return 1;

	default:	/* unknown report */
		/* Unknown report type; pass upstream */
		hid_info(hid, "unknown report type %d\n", report->id);
		break;
	}

	return 0;
}
Пример #11
0
int lg2ff_init(struct hid_device *hid)
{
	struct lg2ff_device *lg2ff;
	struct hid_report *report;
	struct hid_input *hidinput = list_entry(hid->inputs.next,
						struct hid_input, list);
	struct input_dev *dev = hidinput->input;
	int error;

	/* Check that the report looks ok */
	report = hid_validate_report(hid, HID_OUTPUT_REPORT, 0, 1, 7);
	if (!report)
		return -ENODEV;

	lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL);
	if (!lg2ff)
		return -ENOMEM;

	set_bit(FF_RUMBLE, dev->ffbit);

	error = input_ff_create_memless(dev, lg2ff, play_effect);
	if (error) {
		kfree(lg2ff);
		return error;
	}

	lg2ff->report = report;
	report->field[0]->value[0] = 0xf3;
	report->field[0]->value[1] = 0x00;
	report->field[0]->value[2] = 0x00;
	report->field[0]->value[3] = 0x00;
	report->field[0]->value[4] = 0x00;
	report->field[0]->value[5] = 0x00;
	report->field[0]->value[6] = 0x00;

	usbhid_submit_report(hid, report, USB_DIR_OUT);

	hid_info(hid, "Force feedback for Logitech RumblePad/Rumblepad 2 by Anssi Hannula <*****@*****.**>\n");

	return 0;
}
static int zpff_init(struct hid_device *hid)
{
	struct zpff_device *zpff;
	struct hid_report *report;
	struct hid_input *hidinput = list_entry(hid->inputs.next,
						struct hid_input, list);
	struct input_dev *dev = hidinput->input;
	int i, error;

	for (i = 0; i < 4; i++) {
		report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, i, 1);
		if (!report)
			return -ENODEV;
	}

	zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL);
	if (!zpff)
		return -ENOMEM;

	set_bit(FF_RUMBLE, dev->ffbit);

	error = input_ff_create_memless(dev, zpff, zpff_play);
	if (error) {
		kfree(zpff);
		return error;
	}

	zpff->report = report;
	zpff->report->field[0]->value[0] = 0x00;
	zpff->report->field[1]->value[0] = 0x02;
	zpff->report->field[2]->value[0] = 0x00;
	zpff->report->field[3]->value[0] = 0x00;
	usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);

	hid_info(hid, "force feedback for Zeroplus based devices by Anssi Hannula <*****@*****.**>\n");

	return 0;
}
static int px_raw_event(struct hid_device *hid, struct hid_report *report,
	 u8 *data, int size)
{
	int idx = size;

	switch (report->id) {
	case 0:		
		while (--idx > 1) {
			if (data[idx] < 0xE0 || data[idx] > 0xE7)
				continue;
			data[0] |= (1 << (data[idx] - 0xE0));
			data[idx] = 0;
		}
		hid_report_raw_event(hid, HID_INPUT_REPORT, data, size, 0);
		return 1;

	default:	
		
		hid_info(hid, "unknown report type %d\n", report->id);
		break;
	}

	return 0;
}
Пример #14
0
/*
 * Certain Logitech keyboards send in report #3 keys which are far
 * above the logical maximum described in descriptor. This extends
 * the original value of 0x28c of logical maximum to 0x104d
 */
static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
		unsigned int *rsize)
{
	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);

	if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 &&
			rdesc[84] == 0x8c && rdesc[85] == 0x02) {
		hid_info(hdev,
			 "fixing up Logitech keyboard report descriptor\n");
		rdesc[84] = rdesc[89] = 0x4d;
		rdesc[85] = rdesc[90] = 0x10;
	}
	if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 &&
			rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
			rdesc[49] == 0x81 && rdesc[50] == 0x06) {
		hid_info(hdev,
			 "fixing up rel/abs in Logitech report descriptor\n");
		rdesc[33] = rdesc[50] = 0x02;
	}

	switch (hdev->product) {

	case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
		if (*rsize == FFG_RDESC_ORIG_SIZE) {
			hid_info(hdev,
				"fixing up Logitech Wingman Formula Force GP report descriptor\n");
			rdesc = ffg_rdesc_fixed;
			*rsize = sizeof(ffg_rdesc_fixed);
		}
		break;

	/* Several wheels report as this id when operating in emulation mode. */
	case USB_DEVICE_ID_LOGITECH_WHEEL:
		if (*rsize == DF_RDESC_ORIG_SIZE) {
			hid_info(hdev,
				"fixing up Logitech Driving Force report descriptor\n");
			rdesc = df_rdesc_fixed;
			*rsize = sizeof(df_rdesc_fixed);
		}
		break;

	case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
		if (*rsize == MOMO_RDESC_ORIG_SIZE) {
			hid_info(hdev,
				"fixing up Logitech Momo Force (Red) report descriptor\n");
			rdesc = momo_rdesc_fixed;
			*rsize = sizeof(momo_rdesc_fixed);
		}
		break;

	case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
		if (*rsize == MOMO2_RDESC_ORIG_SIZE) {
			hid_info(hdev,
				"fixing up Logitech Momo Racing Force (Black) report descriptor\n");
			rdesc = momo2_rdesc_fixed;
			*rsize = sizeof(momo2_rdesc_fixed);
		}
		break;

	case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
		if (*rsize == FV_RDESC_ORIG_SIZE) {
			hid_info(hdev,
				"fixing up Logitech Formula Vibration report descriptor\n");
			rdesc = fv_rdesc_fixed;
			*rsize = sizeof(fv_rdesc_fixed);
		}
		break;

	case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
		if (*rsize == DFP_RDESC_ORIG_SIZE) {
			hid_info(hdev,
				"fixing up Logitech Driving Force Pro report descriptor\n");
			rdesc = dfp_rdesc_fixed;
			*rsize = sizeof(dfp_rdesc_fixed);
		}
		break;

	case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
		if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
				rdesc[47] == 0x05 && rdesc[48] == 0x09) {
			hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n");
			rdesc[41] = 0x05;
			rdesc[42] = 0x09;
			rdesc[47] = 0x95;
			rdesc[48] = 0x0B;
		}
		break;
	}

	return rdesc;
}
static int valve_sc_init_device(struct valve_sc_device *sc)
{
	int ret;
	struct hid_device *hdev = sc->hdev;
	struct input_dev *input;
	u8 params[6];
	u8 feature;
	u8 serial[64];
	int serial_len;
	char *name, *uniq;
	int name_sz, uniq_sz;

	hid_info(hdev, "Initializing device.\n");

	/* Retrieve controller serial */
	serial[0] = 1;
	ret = valve_sc_send_request(sc, SC_FEATURE_GET_SERIAL,
				    serial, 21,
				    serial, &serial_len);
	if (ret < 0 || serial_len < 1 || serial_len > 62) {
		hid_warn(hdev, "Error while get controller serial: %d\n", -ret);
		serial[1] = '\0';
	}
	else {
		serial[serial_len] = '\0';
	}

	/* Set mouse mode for right pad */
	params[0] = SC_SETTINGS_AUTOMOUSE;
	if (sc->automouse)
		params[1] = SC_SETTINGS_AUTOMOUSE_ON;
	else
		params[1] = SC_SETTINGS_AUTOMOUSE_OFF;
	params[2] = 0;
	params[3] = SC_SETTINGS_ORIENTATION;
	params[4] = sc->orientation;
	params[5] = 0;
	ret = valve_sc_send_request(sc, SC_FEATURE_SETTINGS,
				    params, 6,
				    NULL, NULL);
	if (ret < 0)
		hid_warn(hdev, "Error while disabling mouse: %d\n", -ret);

	/* Disable buttons acting as keys */
	if (sc->autobuttons)
		feature = SC_FEATURE_ENABLE_AUTO_BUTTONS;
	else
		feature = SC_FEATURE_DISABLE_AUTO_BUTTONS;

	ret = valve_sc_send_request(sc, feature,
				    NULL, 0,
				    NULL, NULL);
	if (ret < 0)
		hid_warn(hdev, "Error while setting auto buttons: %d\n", -ret);

	/* Create input device */
	input = input_allocate_device();
	if (!input) {
		hid_err(hdev, "Failed to allocate input device.\n");
		return -ENOMEM;
	}

	sc->input = input;

	input->dev.parent = &hdev->dev;
	input->id.bustype = hdev->bus;
	input->id.vendor = hdev->vendor;
	input->id.product = hdev->product;
	input->id.version = hdev->version;
	name_sz = strlen(hdev->name) + 1;
	name = devm_kzalloc(&input->dev, name_sz, GFP_KERNEL);
	strncpy(name, hdev->name, name_sz);
	input->name = name;
	uniq_sz = serial_len + 1;
	uniq = devm_kzalloc(&input->dev, uniq_sz, GFP_KERNEL);
	strncpy(uniq, &serial[1], serial_len);
	uniq[serial_len] = '\0';
	input->uniq = uniq;

	valve_sc_setup_input(input);

	ret = input_register_device(input);
	if (ret != 0) {
		hid_err(hdev, "Failed to register input device: %d.\n", -ret);
		input_free_device(input);
		sc->input = NULL;
		return ret;
	}
	return 0;
}
Пример #16
0
static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
		unsigned int *rsize)
{
	switch (hdev->product) {
	case USB_DEVICE_ID_KYE_ERGO_525V:
		/* the fixups that need to be done:
		 *   - change led usage page to button for extra buttons
		 *   - report size 8 count 1 must be size 1 count 8 for button
		 *     bitfield
		 *   - change the button usage range to 4-7 for the extra
		 *     buttons
		 */
		if (*rsize >= 75 &&
			rdesc[61] == 0x05 && rdesc[62] == 0x08 &&
			rdesc[63] == 0x19 && rdesc[64] == 0x08 &&
			rdesc[65] == 0x29 && rdesc[66] == 0x0f &&
			rdesc[71] == 0x75 && rdesc[72] == 0x08 &&
			rdesc[73] == 0x95 && rdesc[74] == 0x01) {
			hid_info(hdev,
				 "fixing up Kye/Genius Ergo Mouse "
				 "report descriptor\n");
			rdesc[62] = 0x09;
			rdesc[64] = 0x04;
			rdesc[66] = 0x07;
			rdesc[72] = 0x01;
			rdesc[74] = 0x08;
		}
		break;
	case USB_DEVICE_ID_KYE_EASYPEN_I405X:
		if (*rsize == EASYPEN_I405X_RDESC_ORIG_SIZE) {
			rdesc = easypen_i405x_rdesc_fixed;
			*rsize = sizeof(easypen_i405x_rdesc_fixed);
		}
		break;
	case USB_DEVICE_ID_KYE_MOUSEPEN_I608X:
		if (*rsize == MOUSEPEN_I608X_RDESC_ORIG_SIZE) {
			rdesc = mousepen_i608x_rdesc_fixed;
			*rsize = sizeof(mousepen_i608x_rdesc_fixed);
		}
		break;
	case USB_DEVICE_ID_KYE_EASYPEN_M610X:
		if (*rsize == EASYPEN_M610X_RDESC_ORIG_SIZE) {
			rdesc = easypen_m610x_rdesc_fixed;
			*rsize = sizeof(easypen_m610x_rdesc_fixed);
		}
		break;
	case USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE:
		rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104,
					"Genius Gila Gaming Mouse");
		break;
	case USB_DEVICE_ID_GENIUS_GX_IMPERATOR:
		rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 83,
					"Genius Gx Imperator Keyboard");
		break;
	case USB_DEVICE_ID_GENIUS_MANTICORE:
		rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104,
					"Genius Manticore Keyboard");
		break;
	}
	return rdesc;
}
Пример #17
0
/*
 * There are several variants for 0419:0001:
 *
 * 1. 184 byte report descriptor
 * Vendor specific report #4 has a size of 48 bit,
 * and therefore is not accepted when inspecting the descriptors.
 * As a workaround we reinterpret the report as:
 *   Variable type, count 6, size 8 bit, log. maximum 255
 * The burden to reconstruct the data is moved into user space.
 *
 * 2. 203 byte report descriptor
 * Report #4 has an array field with logical range 0..18 instead of 1..15.
 *
 * 3. 135 byte report descriptor
 * Report #4 has an array field with logical range 0..17 instead of 1..14.
 *
 * 4. 171 byte report descriptor
 * Report #3 has an array field with logical range 0..1 instead of 1..3.
 */
static inline void samsung_irda_dev_trace(struct hid_device *hdev,
		unsigned int rsize)
{
	hid_info(hdev, "fixing up Samsung IrDA %d byte report descriptor\n",
		 rsize);
}
Пример #18
0
/*
 * Certain Logitech keyboards send in report #3 keys which are far
 * above the logical maximum described in descriptor. This extends
 * the original value of 0x28c of logical maximum to 0x104d
 */
static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
		unsigned int *rsize)
{
	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
	struct usb_device_descriptor *udesc;
	__u16 bcdDevice, rev_maj, rev_min;

	if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
			rdesc[84] == 0x8c && rdesc[85] == 0x02) {
		hid_info(hdev,
			 "fixing up Logitech keyboard report descriptor\n");
		rdesc[84] = rdesc[89] = 0x4d;
		rdesc[85] = rdesc[90] = 0x10;
	}
	if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
			rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
			rdesc[49] == 0x81 && rdesc[50] == 0x06) {
		hid_info(hdev,
			 "fixing up rel/abs in Logitech report descriptor\n");
		rdesc[33] = rdesc[50] = 0x02;
	}

	switch (hdev->product) {

	/* Several wheels report as this id when operating in emulation mode. */
	case USB_DEVICE_ID_LOGITECH_WHEEL:
		udesc = &(hid_to_usb_dev(hdev)->descriptor);
		if (!udesc) {
			hid_err(hdev, "NULL USB device descriptor\n");
			break;
		}
		bcdDevice = le16_to_cpu(udesc->bcdDevice);
		rev_maj = bcdDevice >> 8;
		rev_min = bcdDevice & 0xff;

		/* Update the report descriptor for only the Driving Force wheel */
		if (rev_maj == 1 && rev_min == 2 &&
				*rsize == DF_RDESC_ORIG_SIZE) {
			hid_info(hdev,
				"fixing up Logitech Driving Force report descriptor\n");
			rdesc = df_rdesc_fixed;
			*rsize = sizeof(df_rdesc_fixed);
		}
		break;

	case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
		if (*rsize == MOMO_RDESC_ORIG_SIZE) {
			hid_info(hdev,
				"fixing up Logitech Momo Force (Red) report descriptor\n");
			rdesc = momo_rdesc_fixed;
			*rsize = sizeof(momo_rdesc_fixed);
		}
		break;

	case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
		if (*rsize == MOMO2_RDESC_ORIG_SIZE) {
			hid_info(hdev,
				"fixing up Logitech Momo Racing Force (Black) report descriptor\n");
			rdesc = momo2_rdesc_fixed;
			*rsize = sizeof(momo2_rdesc_fixed);
		}
		break;

	case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
		if (*rsize == FV_RDESC_ORIG_SIZE) {
			hid_info(hdev,
				"fixing up Logitech Formula Vibration report descriptor\n");
			rdesc = fv_rdesc_fixed;
			*rsize = sizeof(fv_rdesc_fixed);
		}
		break;

	case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
		if (*rsize == DFP_RDESC_ORIG_SIZE) {
			hid_info(hdev,
				"fixing up Logitech Driving Force Pro report descriptor\n");
			rdesc = dfp_rdesc_fixed;
			*rsize = sizeof(dfp_rdesc_fixed);
		}
		break;

	case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
		if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
				rdesc[47] == 0x05 && rdesc[48] == 0x09) {
			hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n");
			rdesc[41] = 0x05;
			rdesc[42] = 0x09;
			rdesc[47] = 0x95;
			rdesc[48] = 0x0B;
		}
		break;
	}

	return rdesc;
}