0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/hid.h>
0015 #include <linux/input.h>
0016 #include <linux/module.h>
0017 #include <linux/slab.h>
0018
0019 #include "hid-ids.h"
0020
0021 #ifdef CONFIG_HOLTEK_FF
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065 #define HOLTEKFF_MSG_LENGTH 7
0066
0067 static const u8 start_effect_1[] = { 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
0068 static const u8 stop_all4[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
0069 static const u8 stop_all6[] = { 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
0070
0071 struct holtekff_device {
0072 struct hid_field *field;
0073 };
0074
0075 static void holtekff_send(struct holtekff_device *holtekff,
0076 struct hid_device *hid,
0077 const u8 data[HOLTEKFF_MSG_LENGTH])
0078 {
0079 int i;
0080
0081 for (i = 0; i < HOLTEKFF_MSG_LENGTH; i++) {
0082 holtekff->field->value[i] = data[i];
0083 }
0084
0085 dbg_hid("sending %7ph\n", data);
0086
0087 hid_hw_request(hid, holtekff->field->report, HID_REQ_SET_REPORT);
0088 }
0089
0090 static int holtekff_play(struct input_dev *dev, void *data,
0091 struct ff_effect *effect)
0092 {
0093 struct hid_device *hid = input_get_drvdata(dev);
0094 struct holtekff_device *holtekff = data;
0095 int left, right;
0096
0097 u8 buf[HOLTEKFF_MSG_LENGTH] =
0098 { 0x01, 0x01, 0xff, 0xff, 0x10, 0xe0, 0x00 };
0099
0100 left = effect->u.rumble.strong_magnitude;
0101 right = effect->u.rumble.weak_magnitude;
0102 dbg_hid("called with 0x%04x 0x%04x\n", left, right);
0103
0104 if (!left && !right) {
0105 holtekff_send(holtekff, hid, stop_all6);
0106 return 0;
0107 }
0108
0109 if (left)
0110 buf[1] |= 0x80;
0111 if (right)
0112 buf[1] |= 0x40;
0113
0114
0115 buf[6] = min(0xf, (left >> 12) + (right >> 12));
0116
0117 holtekff_send(holtekff, hid, buf);
0118 holtekff_send(holtekff, hid, start_effect_1);
0119
0120 return 0;
0121 }
0122
0123 static int holtekff_init(struct hid_device *hid)
0124 {
0125 struct holtekff_device *holtekff;
0126 struct hid_report *report;
0127 struct hid_input *hidinput;
0128 struct list_head *report_list =
0129 &hid->report_enum[HID_OUTPUT_REPORT].report_list;
0130 struct input_dev *dev;
0131 int error;
0132
0133 if (list_empty(&hid->inputs)) {
0134 hid_err(hid, "no inputs found\n");
0135 return -ENODEV;
0136 }
0137 hidinput = list_entry(hid->inputs.next, struct hid_input, list);
0138 dev = hidinput->input;
0139
0140 if (list_empty(report_list)) {
0141 hid_err(hid, "no output report found\n");
0142 return -ENODEV;
0143 }
0144
0145 report = list_entry(report_list->next, struct hid_report, list);
0146
0147 if (report->maxfield < 1 || report->field[0]->report_count != 7) {
0148 hid_err(hid, "unexpected output report layout\n");
0149 return -ENODEV;
0150 }
0151
0152 holtekff = kzalloc(sizeof(*holtekff), GFP_KERNEL);
0153 if (!holtekff)
0154 return -ENOMEM;
0155
0156 set_bit(FF_RUMBLE, dev->ffbit);
0157
0158 holtekff->field = report->field[0];
0159
0160
0161 holtekff_send(holtekff, hid, stop_all4);
0162 holtekff_send(holtekff, hid, stop_all6);
0163
0164 error = input_ff_create_memless(dev, holtekff, holtekff_play);
0165 if (error) {
0166 kfree(holtekff);
0167 return error;
0168 }
0169
0170 hid_info(hid, "Force feedback for Holtek On Line Grip based devices by Anssi Hannula <anssi.hannula@iki.fi>\n");
0171
0172 return 0;
0173 }
0174 #else
0175 static inline int holtekff_init(struct hid_device *hid)
0176 {
0177 return 0;
0178 }
0179 #endif
0180
0181 static int holtek_probe(struct hid_device *hdev, const struct hid_device_id *id)
0182 {
0183 int ret;
0184
0185 ret = hid_parse(hdev);
0186 if (ret) {
0187 hid_err(hdev, "parse failed\n");
0188 goto err;
0189 }
0190
0191 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
0192 if (ret) {
0193 hid_err(hdev, "hw start failed\n");
0194 goto err;
0195 }
0196
0197 holtekff_init(hdev);
0198
0199 return 0;
0200 err:
0201 return ret;
0202 }
0203
0204 static const struct hid_device_id holtek_devices[] = {
0205 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
0206 { }
0207 };
0208 MODULE_DEVICE_TABLE(hid, holtek_devices);
0209
0210 static struct hid_driver holtek_driver = {
0211 .name = "holtek",
0212 .id_table = holtek_devices,
0213 .probe = holtek_probe,
0214 };
0215 module_hid_driver(holtek_driver);
0216
0217 MODULE_LICENSE("GPL");
0218 MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
0219 MODULE_DESCRIPTION("Force feedback support for Holtek On Line Grip based devices");