This source file includes following definitions.
- holtekff_send
- holtekff_play
- holtekff_init
- holtekff_init
- holtek_probe
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 #include <linux/hid.h>
  15 #include <linux/input.h>
  16 #include <linux/module.h>
  17 #include <linux/slab.h>
  18 
  19 #include "hid-ids.h"
  20 
  21 #ifdef CONFIG_HOLTEK_FF
  22 
  23 
  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 
  51 
  52 
  53 
  54 
  55 
  56 
  57 
  58 
  59 
  60 
  61 
  62 
  63 
  64 
  65 #define HOLTEKFF_MSG_LENGTH     7
  66 
  67 static const u8 start_effect_1[] = { 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
  68 static const u8 stop_all4[] =      { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  69 static const u8 stop_all6[] =      { 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  70 
  71 struct holtekff_device {
  72         struct hid_field *field;
  73 };
  74 
  75 static void holtekff_send(struct holtekff_device *holtekff,
  76                           struct hid_device *hid,
  77                           const u8 data[HOLTEKFF_MSG_LENGTH])
  78 {
  79         int i;
  80 
  81         for (i = 0; i < HOLTEKFF_MSG_LENGTH; i++) {
  82                 holtekff->field->value[i] = data[i];
  83         }
  84 
  85         dbg_hid("sending %7ph\n", data);
  86 
  87         hid_hw_request(hid, holtekff->field->report, HID_REQ_SET_REPORT);
  88 }
  89 
  90 static int holtekff_play(struct input_dev *dev, void *data,
  91                          struct ff_effect *effect)
  92 {
  93         struct hid_device *hid = input_get_drvdata(dev);
  94         struct holtekff_device *holtekff = data;
  95         int left, right;
  96         
  97         u8 buf[HOLTEKFF_MSG_LENGTH] =
  98                 { 0x01, 0x01, 0xff, 0xff, 0x10, 0xe0, 0x00 };
  99 
 100         left = effect->u.rumble.strong_magnitude;
 101         right = effect->u.rumble.weak_magnitude;
 102         dbg_hid("called with 0x%04x 0x%04x\n", left, right);
 103 
 104         if (!left && !right) {
 105                 holtekff_send(holtekff, hid, stop_all6);
 106                 return 0;
 107         }
 108 
 109         if (left)
 110                 buf[1] |= 0x80;
 111         if (right)
 112                 buf[1] |= 0x40;
 113 
 114         
 115         buf[6] = min(0xf, (left >> 12) + (right >> 12));
 116 
 117         holtekff_send(holtekff, hid, buf);
 118         holtekff_send(holtekff, hid, start_effect_1);
 119 
 120         return 0;
 121 }
 122 
 123 static int holtekff_init(struct hid_device *hid)
 124 {
 125         struct holtekff_device *holtekff;
 126         struct hid_report *report;
 127         struct hid_input *hidinput;
 128         struct list_head *report_list =
 129                         &hid->report_enum[HID_OUTPUT_REPORT].report_list;
 130         struct input_dev *dev;
 131         int error;
 132 
 133         if (list_empty(&hid->inputs)) {
 134                 hid_err(hid, "no inputs found\n");
 135                 return -ENODEV;
 136         }
 137         hidinput = list_entry(hid->inputs.next, struct hid_input, list);
 138         dev = hidinput->input;
 139 
 140         if (list_empty(report_list)) {
 141                 hid_err(hid, "no output report found\n");
 142                 return -ENODEV;
 143         }
 144 
 145         report = list_entry(report_list->next, struct hid_report, list);
 146 
 147         if (report->maxfield < 1 || report->field[0]->report_count != 7) {
 148                 hid_err(hid, "unexpected output report layout\n");
 149                 return -ENODEV;
 150         }
 151 
 152         holtekff = kzalloc(sizeof(*holtekff), GFP_KERNEL);
 153         if (!holtekff)
 154                 return -ENOMEM;
 155 
 156         set_bit(FF_RUMBLE, dev->ffbit);
 157 
 158         holtekff->field = report->field[0];
 159 
 160         
 161         holtekff_send(holtekff, hid, stop_all4);
 162         holtekff_send(holtekff, hid, stop_all6);
 163 
 164         error = input_ff_create_memless(dev, holtekff, holtekff_play);
 165         if (error) {
 166                 kfree(holtekff);
 167                 return error;
 168         }
 169 
 170         hid_info(hid, "Force feedback for Holtek On Line Grip based devices by Anssi Hannula <anssi.hannula@iki.fi>\n");
 171 
 172         return 0;
 173 }
 174 #else
 175 static inline int holtekff_init(struct hid_device *hid)
 176 {
 177         return 0;
 178 }
 179 #endif
 180 
 181 static int holtek_probe(struct hid_device *hdev, const struct hid_device_id *id)
 182 {
 183         int ret;
 184 
 185         ret = hid_parse(hdev);
 186         if (ret) {
 187                 hid_err(hdev, "parse failed\n");
 188                 goto err;
 189         }
 190 
 191         ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
 192         if (ret) {
 193                 hid_err(hdev, "hw start failed\n");
 194                 goto err;
 195         }
 196 
 197         holtekff_init(hdev);
 198 
 199         return 0;
 200 err:
 201         return ret;
 202 }
 203 
 204 static const struct hid_device_id holtek_devices[] = {
 205         { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
 206         { }
 207 };
 208 MODULE_DEVICE_TABLE(hid, holtek_devices);
 209 
 210 static struct hid_driver holtek_driver = {
 211         .name = "holtek",
 212         .id_table = holtek_devices,
 213         .probe = holtek_probe,
 214 };
 215 module_hid_driver(holtek_driver);
 216 
 217 MODULE_LICENSE("GPL");
 218 MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
 219 MODULE_DESCRIPTION("Force feedback support for Holtek On Line Grip based devices");