104561c5aa243c98cae93cde27e05740df787e692Ignaz Forster/*
204561c5aa243c98cae93cde27e05740df787e692Ignaz Forster *  Force feedback support for EMS Trio Linker Plus II
304561c5aa243c98cae93cde27e05740df787e692Ignaz Forster *
404561c5aa243c98cae93cde27e05740df787e692Ignaz Forster *  Copyright (c) 2010 Ignaz Forster <ignaz.forster@gmx.de>
504561c5aa243c98cae93cde27e05740df787e692Ignaz Forster */
604561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
704561c5aa243c98cae93cde27e05740df787e692Ignaz Forster/*
804561c5aa243c98cae93cde27e05740df787e692Ignaz Forster * This program is free software; you can redistribute it and/or modify
904561c5aa243c98cae93cde27e05740df787e692Ignaz Forster * it under the terms of the GNU General Public License as published by
1004561c5aa243c98cae93cde27e05740df787e692Ignaz Forster * the Free Software Foundation; either version 2 of the License, or
1104561c5aa243c98cae93cde27e05740df787e692Ignaz Forster * (at your option) any later version.
1204561c5aa243c98cae93cde27e05740df787e692Ignaz Forster *
1304561c5aa243c98cae93cde27e05740df787e692Ignaz Forster * This program is distributed in the hope that it will be useful,
1404561c5aa243c98cae93cde27e05740df787e692Ignaz Forster * but WITHOUT ANY WARRANTY; without even the implied warranty of
1504561c5aa243c98cae93cde27e05740df787e692Ignaz Forster * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1604561c5aa243c98cae93cde27e05740df787e692Ignaz Forster * GNU General Public License for more details.
1704561c5aa243c98cae93cde27e05740df787e692Ignaz Forster *
1804561c5aa243c98cae93cde27e05740df787e692Ignaz Forster * You should have received a copy of the GNU General Public License
1904561c5aa243c98cae93cde27e05740df787e692Ignaz Forster * along with this program; if not, write to the Free Software
2004561c5aa243c98cae93cde27e05740df787e692Ignaz Forster * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2104561c5aa243c98cae93cde27e05740df787e692Ignaz Forster */
2204561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
2304561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
2404561c5aa243c98cae93cde27e05740df787e692Ignaz Forster#include <linux/hid.h>
2504561c5aa243c98cae93cde27e05740df787e692Ignaz Forster#include <linux/input.h>
268f86a2c3cb90e8bb0733de2d2b0abbe7050bb536Paul Gortmaker#include <linux/module.h>
2704561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
2804561c5aa243c98cae93cde27e05740df787e692Ignaz Forster#include "hid-ids.h"
2904561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
3004561c5aa243c98cae93cde27e05740df787e692Ignaz Forsterstruct emsff_device {
3104561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	struct hid_report *report;
3204561c5aa243c98cae93cde27e05740df787e692Ignaz Forster};
3304561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
3404561c5aa243c98cae93cde27e05740df787e692Ignaz Forsterstatic int emsff_play(struct input_dev *dev, void *data,
3504561c5aa243c98cae93cde27e05740df787e692Ignaz Forster			 struct ff_effect *effect)
3604561c5aa243c98cae93cde27e05740df787e692Ignaz Forster{
3704561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	struct hid_device *hid = input_get_drvdata(dev);
3804561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	struct emsff_device *emsff = data;
3904561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	int weak, strong;
4004561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
4104561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	weak = effect->u.rumble.weak_magnitude;
4204561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	strong = effect->u.rumble.strong_magnitude;
4304561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
4404561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	dbg_hid("called with 0x%04x 0x%04x\n", strong, weak);
4504561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
4604561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	weak = weak * 0xff / 0xffff;
4704561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	strong = strong * 0xff / 0xffff;
4804561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
4904561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	emsff->report->field[0]->value[1] = weak;
5004561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	emsff->report->field[0]->value[2] = strong;
5104561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
5204561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	dbg_hid("running with 0x%02x 0x%02x\n", strong, weak);
53d881427253da011495f4193663d809d0e9dfa215Benjamin Tissoires	hid_hw_request(hid, emsff->report, HID_REQ_SET_REPORT);
5404561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
5504561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	return 0;
5604561c5aa243c98cae93cde27e05740df787e692Ignaz Forster}
5704561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
5804561c5aa243c98cae93cde27e05740df787e692Ignaz Forsterstatic int emsff_init(struct hid_device *hid)
5904561c5aa243c98cae93cde27e05740df787e692Ignaz Forster{
6004561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	struct emsff_device *emsff;
6104561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	struct hid_report *report;
6204561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	struct hid_input *hidinput = list_first_entry(&hid->inputs,
6304561c5aa243c98cae93cde27e05740df787e692Ignaz Forster						struct hid_input, list);
6404561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	struct list_head *report_list =
6504561c5aa243c98cae93cde27e05740df787e692Ignaz Forster			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
6604561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	struct input_dev *dev = hidinput->input;
6704561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	int error;
6804561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
6904561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	if (list_empty(report_list)) {
704291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_err(hid, "no output reports found\n");
7104561c5aa243c98cae93cde27e05740df787e692Ignaz Forster		return -ENODEV;
7204561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	}
7304561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
7404561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	report = list_first_entry(report_list, struct hid_report, list);
7504561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	if (report->maxfield < 1) {
764291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_err(hid, "no fields in the report\n");
7704561c5aa243c98cae93cde27e05740df787e692Ignaz Forster		return -ENODEV;
7804561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	}
7904561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
8004561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	if (report->field[0]->report_count < 7) {
814291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_err(hid, "not enough values in the field\n");
8204561c5aa243c98cae93cde27e05740df787e692Ignaz Forster		return -ENODEV;
8304561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	}
8404561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
8504561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	emsff = kzalloc(sizeof(struct emsff_device), GFP_KERNEL);
8604561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	if (!emsff)
8704561c5aa243c98cae93cde27e05740df787e692Ignaz Forster		return -ENOMEM;
8804561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
8904561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	set_bit(FF_RUMBLE, dev->ffbit);
9004561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
9104561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	error = input_ff_create_memless(dev, emsff, emsff_play);
9204561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	if (error) {
9304561c5aa243c98cae93cde27e05740df787e692Ignaz Forster		kfree(emsff);
9404561c5aa243c98cae93cde27e05740df787e692Ignaz Forster		return error;
9504561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	}
9604561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
9704561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	emsff->report = report;
9804561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	emsff->report->field[0]->value[0] = 0x01;
9904561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	emsff->report->field[0]->value[1] = 0x00;
10004561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	emsff->report->field[0]->value[2] = 0x00;
10104561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	emsff->report->field[0]->value[3] = 0x00;
10204561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	emsff->report->field[0]->value[4] = 0x00;
10304561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	emsff->report->field[0]->value[5] = 0x00;
10404561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	emsff->report->field[0]->value[6] = 0x00;
105d881427253da011495f4193663d809d0e9dfa215Benjamin Tissoires	hid_hw_request(hid, emsff->report, HID_REQ_SET_REPORT);
10604561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
1074291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches	hid_info(hid, "force feedback for EMS based devices by Ignaz Forster <ignaz.forster@gmx.de>\n");
10804561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
10904561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	return 0;
11004561c5aa243c98cae93cde27e05740df787e692Ignaz Forster}
11104561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
11204561c5aa243c98cae93cde27e05740df787e692Ignaz Forsterstatic int ems_probe(struct hid_device *hdev, const struct hid_device_id *id)
11304561c5aa243c98cae93cde27e05740df787e692Ignaz Forster{
11404561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	int ret;
11504561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
11604561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	ret = hid_parse(hdev);
11704561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	if (ret) {
1184291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_err(hdev, "parse failed\n");
11904561c5aa243c98cae93cde27e05740df787e692Ignaz Forster		goto err;
12004561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	}
12104561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
12204561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
12304561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	if (ret) {
1244291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_err(hdev, "hw start failed\n");
12504561c5aa243c98cae93cde27e05740df787e692Ignaz Forster		goto err;
12604561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	}
12704561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
1282dcd9543a28da523a179a13b1eefa5f9b8e05d72Axel Lin	ret = emsff_init(hdev);
1292dcd9543a28da523a179a13b1eefa5f9b8e05d72Axel Lin	if (ret) {
1302dcd9543a28da523a179a13b1eefa5f9b8e05d72Axel Lin		dev_err(&hdev->dev, "force feedback init failed\n");
1312dcd9543a28da523a179a13b1eefa5f9b8e05d72Axel Lin		hid_hw_stop(hdev);
1322dcd9543a28da523a179a13b1eefa5f9b8e05d72Axel Lin		goto err;
1332dcd9543a28da523a179a13b1eefa5f9b8e05d72Axel Lin	}
13404561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
13504561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	return 0;
13604561c5aa243c98cae93cde27e05740df787e692Ignaz Forstererr:
13704561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	return ret;
13804561c5aa243c98cae93cde27e05740df787e692Ignaz Forster}
13904561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
14004561c5aa243c98cae93cde27e05740df787e692Ignaz Forsterstatic const struct hid_device_id ems_devices[] = {
14105ee28387946ca9936956a6e45f822c0c41dfc87Jiri Kosina	{ HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
14204561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	{ }
14304561c5aa243c98cae93cde27e05740df787e692Ignaz Forster};
14404561c5aa243c98cae93cde27e05740df787e692Ignaz ForsterMODULE_DEVICE_TABLE(hid, ems_devices);
14504561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
14604561c5aa243c98cae93cde27e05740df787e692Ignaz Forsterstatic struct hid_driver ems_driver = {
14704561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	.name = "hkems",
14804561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	.id_table = ems_devices,
14904561c5aa243c98cae93cde27e05740df787e692Ignaz Forster	.probe = ems_probe,
15004561c5aa243c98cae93cde27e05740df787e692Ignaz Forster};
151f425458eafd51b6b5ab64f407922e1198c567cb2H Hartley Sweetenmodule_hid_driver(ems_driver);
15204561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
15304561c5aa243c98cae93cde27e05740df787e692Ignaz ForsterMODULE_LICENSE("GPL");
15404561c5aa243c98cae93cde27e05740df787e692Ignaz Forster
155