brintos

brintos / linux-shallow public Read only

0
0
Text · 3.1 KiB · aacf7f1 Raw
143 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Force feedback support for Zeroplus based devices4 *5 *  Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com>6 */7 8/*9 */10 11 12#include <linux/hid.h>13#include <linux/input.h>14#include <linux/slab.h>15#include <linux/module.h>16 17#include "hid-ids.h"18 19#ifdef CONFIG_ZEROPLUS_FF20 21struct zpff_device {22	struct hid_report *report;23};24 25static int zpff_play(struct input_dev *dev, void *data,26			 struct ff_effect *effect)27{28	struct hid_device *hid = input_get_drvdata(dev);29	struct zpff_device *zpff = data;30	int left, right;31 32	/*33	 * The following is specified the other way around in the Zeroplus34	 * datasheet but the order below is correct for the XFX Executioner;35	 * however it is possible that the XFX Executioner is an exception36	 */37 38	left = effect->u.rumble.strong_magnitude;39	right = effect->u.rumble.weak_magnitude;40	dbg_hid("called with 0x%04x 0x%04x\n", left, right);41 42	left = left * 0x7f / 0xffff;43	right = right * 0x7f / 0xffff;44 45	zpff->report->field[2]->value[0] = left;46	zpff->report->field[3]->value[0] = right;47	dbg_hid("running with 0x%02x 0x%02x\n", left, right);48	hid_hw_request(hid, zpff->report, HID_REQ_SET_REPORT);49 50	return 0;51}52 53static int zpff_init(struct hid_device *hid)54{55	struct zpff_device *zpff;56	struct hid_report *report;57	struct hid_input *hidinput;58	struct input_dev *dev;59	int i, error;60 61	if (list_empty(&hid->inputs)) {62		hid_err(hid, "no inputs found\n");63		return -ENODEV;64	}65	hidinput = list_entry(hid->inputs.next, struct hid_input, list);66	dev = hidinput->input;67 68	for (i = 0; i < 4; i++) {69		report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, i, 1);70		if (!report)71			return -ENODEV;72	}73 74	zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL);75	if (!zpff)76		return -ENOMEM;77 78	set_bit(FF_RUMBLE, dev->ffbit);79 80	error = input_ff_create_memless(dev, zpff, zpff_play);81	if (error) {82		kfree(zpff);83		return error;84	}85 86	zpff->report = report;87	zpff->report->field[0]->value[0] = 0x00;88	zpff->report->field[1]->value[0] = 0x02;89	zpff->report->field[2]->value[0] = 0x00;90	zpff->report->field[3]->value[0] = 0x00;91	hid_hw_request(hid, zpff->report, HID_REQ_SET_REPORT);92 93	hid_info(hid, "force feedback for Zeroplus based devices by Anssi Hannula <anssi.hannula@gmail.com>\n");94 95	return 0;96}97#else98static inline int zpff_init(struct hid_device *hid)99{100	return 0;101}102#endif103 104static int zp_probe(struct hid_device *hdev, const struct hid_device_id *id)105{106	int ret;107 108	ret = hid_parse(hdev);109	if (ret) {110		hid_err(hdev, "parse failed\n");111		goto err;112	}113 114	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);115	if (ret) {116		hid_err(hdev, "hw start failed\n");117		goto err;118	}119 120	zpff_init(hdev);121 122	return 0;123err:124	return ret;125}126 127static const struct hid_device_id zp_devices[] = {128	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },129	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },130	{ }131};132MODULE_DEVICE_TABLE(hid, zp_devices);133 134static struct hid_driver zp_driver = {135	.name = "zeroplus",136	.id_table = zp_devices,137	.probe = zp_probe,138};139module_hid_driver(zp_driver);140 141MODULE_DESCRIPTION("Force feedback support for Zeroplus based devices");142MODULE_LICENSE("GPL");143