Blame view

drivers/hid/hid-gaff.c 3.99 KB
1a59d1b8e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
42859e0bd   Lukasz Lubojanski   HID: force feedba...
2
3
4
5
6
7
  /*
   *  Force feedback support for GreenAsia (Product ID 0x12) based devices
   *
   *  The devices are distributed under various names and the same USB device ID
   *  can be used in many game controllers.
   *
42859e0bd   Lukasz Lubojanski   HID: force feedba...
8
9
10
11
12
13
14
   *  0e8f:0012 "GreenAsia Inc.    USB Joystick     "
   *   - tested with MANTA Warior MM816 and SpeedLink Strike2 SL-6635.
   *
   *  Copyright (c) 2008 Lukasz Lubojanski <lukasz@lubojanski.info>
   */
  
  /*
42859e0bd   Lukasz Lubojanski   HID: force feedba...
15
16
17
   */
  
  #include <linux/input.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
18
  #include <linux/slab.h>
42859e0bd   Lukasz Lubojanski   HID: force feedba...
19
  #include <linux/hid.h>
8f86a2c3c   Paul Gortmaker   hid: Add module.h...
20
  #include <linux/module.h>
42859e0bd   Lukasz Lubojanski   HID: force feedba...
21
  #include "hid-ids.h"
0f6f4319a   Jiri Kosina   HID: fix hid-ff d...
22
23
  
  #ifdef CONFIG_GREENASIA_FF
42859e0bd   Lukasz Lubojanski   HID: force feedba...
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  
  struct gaff_device {
  	struct hid_report *report;
  };
  
  static int hid_gaff_play(struct input_dev *dev, void *data,
  			 struct ff_effect *effect)
  {
  	struct hid_device *hid = input_get_drvdata(dev);
  	struct gaff_device *gaff = data;
  	int left, right;
  
  	left = effect->u.rumble.strong_magnitude;
  	right = effect->u.rumble.weak_magnitude;
  
  	dbg_hid("called with 0x%04x 0x%04x", left, right);
  
  	left = left * 0xfe / 0xffff;
  	right = right * 0xfe / 0xffff;
  
  	gaff->report->field[0]->value[0] = 0x51;
  	gaff->report->field[0]->value[1] = 0x0;
  	gaff->report->field[0]->value[2] = right;
  	gaff->report->field[0]->value[3] = 0;
  	gaff->report->field[0]->value[4] = left;
  	gaff->report->field[0]->value[5] = 0;
  	dbg_hid("running with 0x%02x 0x%02x", left, right);
d88142725   Benjamin Tissoires   HID: use hid_hw_r...
51
  	hid_hw_request(hid, gaff->report, HID_REQ_SET_REPORT);
42859e0bd   Lukasz Lubojanski   HID: force feedba...
52
53
54
55
56
  
  	gaff->report->field[0]->value[0] = 0xfa;
  	gaff->report->field[0]->value[1] = 0xfe;
  	gaff->report->field[0]->value[2] = 0x0;
  	gaff->report->field[0]->value[4] = 0x0;
d88142725   Benjamin Tissoires   HID: use hid_hw_r...
57
  	hid_hw_request(hid, gaff->report, HID_REQ_SET_REPORT);
42859e0bd   Lukasz Lubojanski   HID: force feedba...
58
59
60
61
62
63
64
65
  
  	return 0;
  }
  
  static int gaff_init(struct hid_device *hid)
  {
  	struct gaff_device *gaff;
  	struct hid_report *report;
d9d4b1e46   Alan Stern   HID: Fix assumpti...
66
  	struct hid_input *hidinput;
42859e0bd   Lukasz Lubojanski   HID: force feedba...
67
68
69
  	struct list_head *report_list =
  			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
  	struct list_head *report_ptr = report_list;
d9d4b1e46   Alan Stern   HID: Fix assumpti...
70
  	struct input_dev *dev;
42859e0bd   Lukasz Lubojanski   HID: force feedba...
71
  	int error;
d9d4b1e46   Alan Stern   HID: Fix assumpti...
72
73
74
75
76
77
78
  	if (list_empty(&hid->inputs)) {
  		hid_err(hid, "no inputs found
  ");
  		return -ENODEV;
  	}
  	hidinput = list_entry(hid->inputs.next, struct hid_input, list);
  	dev = hidinput->input;
42859e0bd   Lukasz Lubojanski   HID: force feedba...
79
  	if (list_empty(report_list)) {
4291ee305   Joe Perches   HID: Add and use ...
80
81
  		hid_err(hid, "no output reports found
  ");
42859e0bd   Lukasz Lubojanski   HID: force feedba...
82
83
84
85
86
87
88
  		return -ENODEV;
  	}
  
  	report_ptr = report_ptr->next;
  
  	report = list_entry(report_ptr, struct hid_report, list);
  	if (report->maxfield < 1) {
4291ee305   Joe Perches   HID: Add and use ...
89
90
  		hid_err(hid, "no fields in the report
  ");
42859e0bd   Lukasz Lubojanski   HID: force feedba...
91
92
93
94
  		return -ENODEV;
  	}
  
  	if (report->field[0]->report_count < 6) {
4291ee305   Joe Perches   HID: Add and use ...
95
96
  		hid_err(hid, "not enough values in the field
  ");
42859e0bd   Lukasz Lubojanski   HID: force feedba...
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  		return -ENODEV;
  	}
  
  	gaff = kzalloc(sizeof(struct gaff_device), GFP_KERNEL);
  	if (!gaff)
  		return -ENOMEM;
  
  	set_bit(FF_RUMBLE, dev->ffbit);
  
  	error = input_ff_create_memless(dev, gaff, hid_gaff_play);
  	if (error) {
  		kfree(gaff);
  		return error;
  	}
  
  	gaff->report = report;
  	gaff->report->field[0]->value[0] = 0x51;
  	gaff->report->field[0]->value[1] = 0x00;
  	gaff->report->field[0]->value[2] = 0x00;
  	gaff->report->field[0]->value[3] = 0x00;
d88142725   Benjamin Tissoires   HID: use hid_hw_r...
117
  	hid_hw_request(hid, gaff->report, HID_REQ_SET_REPORT);
42859e0bd   Lukasz Lubojanski   HID: force feedba...
118
119
120
  
  	gaff->report->field[0]->value[0] = 0xfa;
  	gaff->report->field[0]->value[1] = 0xfe;
d88142725   Benjamin Tissoires   HID: use hid_hw_r...
121
  	hid_hw_request(hid, gaff->report, HID_REQ_SET_REPORT);
42859e0bd   Lukasz Lubojanski   HID: force feedba...
122

4291ee305   Joe Perches   HID: Add and use ...
123
124
  	hid_info(hid, "Force Feedback for GreenAsia 0x12 devices by Lukasz Lubojanski <lukasz@lubojanski.info>
  ");
42859e0bd   Lukasz Lubojanski   HID: force feedba...
125
126
127
  
  	return 0;
  }
0f6f4319a   Jiri Kosina   HID: fix hid-ff d...
128
129
130
131
132
133
  #else
  static inline int gaff_init(struct hid_device *hdev)
  {
  	return 0;
  }
  #endif
42859e0bd   Lukasz Lubojanski   HID: force feedba...
134
135
136
137
138
139
140
141
142
  
  static int ga_probe(struct hid_device *hdev, const struct hid_device_id *id)
  {
  	int ret;
  
  	dev_dbg(&hdev->dev, "Greenasia HID hardware probe...");
  
  	ret = hid_parse(hdev);
  	if (ret) {
4291ee305   Joe Perches   HID: Add and use ...
143
144
  		hid_err(hdev, "parse failed
  ");
42859e0bd   Lukasz Lubojanski   HID: force feedba...
145
146
147
148
149
  		goto err;
  	}
  
  	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
  	if (ret) {
4291ee305   Joe Perches   HID: Add and use ...
150
151
  		hid_err(hdev, "hw start failed
  ");
42859e0bd   Lukasz Lubojanski   HID: force feedba...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  		goto err;
  	}
  
  	gaff_init(hdev);
  
  	return 0;
  err:
  	return ret;
  }
  
  static const struct hid_device_id ga_devices[] = {
  	{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012),  },
  	{ }
  };
  MODULE_DEVICE_TABLE(hid, ga_devices);
  
  static struct hid_driver ga_driver = {
  	.name = "greenasia",
  	.id_table = ga_devices,
  	.probe = ga_probe,
  };
f425458ea   H Hartley Sweeten   HID: Use module_h...
173
  module_hid_driver(ga_driver);
42859e0bd   Lukasz Lubojanski   HID: force feedba...
174

42859e0bd   Lukasz Lubojanski   HID: force feedba...
175
  MODULE_LICENSE("GPL");