aboutsummaryrefslogtreecommitdiff
path: root/hid-tmt300rs.c
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2020-07-10 22:04:12 +0300
committerGitHub <noreply@github.com>2020-07-10 22:04:12 +0300
commit675cad6d635be00c166b5ce23a79e32edd694bc8 (patch)
tree6c679e543dbf55e87eb7946a4b3b972e59dc3984 /hid-tmt300rs.c
parent6faa9ae6a8cf242679ce4e493a66fcb31d231c09 (diff)
parent4d82a0fdfb95cdea2fd904c3ee33c1c6f603d153 (diff)
downloadhid-tmff2-675cad6d635be00c166b5ce23a79e32edd694bc8.tar.gz
hid-tmff2-675cad6d635be00c166b5ce23a79e32edd694bc8.zip
Merge pull request #2 from Kimplul/memory
Memory
Diffstat (limited to 'hid-tmt300rs.c')
-rw-r--r--hid-tmt300rs.c992
1 files changed, 992 insertions, 0 deletions
diff --git a/hid-tmt300rs.c b/hid-tmt300rs.c
new file mode 100644
index 0000000..39747cd
--- /dev/null
+++ b/hid-tmt300rs.c
@@ -0,0 +1,992 @@
+#include "hid-tmt300rs.h"
+
+static void t300rs_int_callback(struct urb *urb){
+ if(urb->status){
+ hid_warn(urb->dev, "urb status %i received\n", urb->status);
+ }
+
+ usb_free_urb(urb);
+}
+
+static struct t300rs_device_entry *t300rs_get_device(struct hid_device *hdev){
+ struct t300rs_data *drv_data;
+ struct t300rs_device_entry *t300rs;
+
+ spin_lock_irqsave(&lock, lock_flags);
+ drv_data = hid_get_drvdata(hdev);
+ if(!drv_data){
+ hid_err(hdev, "private data not found\n");
+ return NULL;
+ }
+
+ t300rs = drv_data->device_props;
+ if(!t300rs){
+ hid_err(hdev, "device properties not found\n");
+ return NULL;
+ }
+ spin_unlock_irqrestore(&lock, lock_flags);
+
+ return t300rs;
+}
+
+static int t300rs_send_int(struct input_dev *dev, u8 *send_buffer, int *trans){
+ struct hid_device *hdev = input_get_drvdata(dev);
+ struct t300rs_device_entry *t300rs;
+ struct usb_device *usbdev;
+ struct usb_interface *usbif;
+ struct usb_host_endpoint *ep;
+ struct urb *urb = usb_alloc_urb(0, GFP_ATOMIC);
+
+ t300rs = t300rs_get_device(hdev);
+ if(!t300rs){
+ hid_err(hdev, "could not get device\n");
+ }
+
+ usbdev = t300rs->usbdev;
+ usbif = t300rs->usbif;
+ ep = &usbif->cur_altsetting->endpoint[1];
+
+ usb_fill_int_urb(
+ urb,
+ usbdev,
+ usb_sndintpipe(usbdev, 1),
+ send_buffer,
+ T300RS_BUFFER_LENGTH,
+ t300rs_int_callback,
+ hdev,
+ ep->desc.bInterval
+ );
+
+ return usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int t300rs_play_effect(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state){
+ u8 *send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_ATOMIC);
+ int ret, trans;
+
+ send_buffer[0] = 0x60;
+ send_buffer[2] = state->effect.id + 1;
+ send_buffer[3] = 0x89;
+ send_buffer[4] = 0x01;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed starting effect play\n");
+ }
+
+ kfree(send_buffer);
+ return ret;
+}
+
+static int t300rs_stop_effect(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state){
+ u8 *send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_ATOMIC);
+ int ret, trans;
+
+ send_buffer[0] = 0x60;
+ send_buffer[2] = state->effect.id + 1;
+ send_buffer[3] = 0x89;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed stopping effect play\n");
+ }
+
+ kfree(send_buffer);
+ return ret;
+}
+
+static void t300rs_fill_envelope(u8 *send_buffer, int i, s16 level, u16 duration, struct ff_envelope *envelope){
+ u16 attack_length = (duration * envelope->attack_length) / 0x7fff;
+ u16 attack_level = (level * envelope->attack_level) / 0x7fff;
+ u16 fade_length = (duration * envelope->fade_length) / 0x7fff;
+ u16 fade_level = (level * envelope->fade_level) / 0x7fff;
+
+ attack_length = cpu_to_le16(attack_length);
+ attack_level = cpu_to_le16(attack_level);
+ fade_length = cpu_to_le16(fade_length);
+ fade_level = cpu_to_le16(fade_level);
+
+ send_buffer[i ] = attack_length & 0xff;
+ send_buffer[i + 1] = attack_length >> 8;
+ send_buffer[i + 2] = attack_level & 0xff;
+ send_buffer[i + 3] = attack_level >> 8;
+ send_buffer[i + 4] = fade_length & 0xff;
+ send_buffer[i + 5] = fade_length >> 8;
+ send_buffer[i + 6] = fade_level & 0xff;
+ send_buffer[i + 7] = fade_level >> 8;
+}
+
+static int t300rs_upload_constant(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state){
+ u8 *send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_ATOMIC);
+ struct ff_effect effect = state->effect;
+ struct ff_constant_effect constant = state->effect.u.constant;
+ s16 level, le_level;
+ u16 duration, le_offset, le_duration;
+
+ int ret, trans;
+
+ /* currently this driver doesn't support dynamic effect updating quite like
+ * many games would assume. There's not a huge drawback to this method, the
+ * wheel maybe feels a bit more jittery because of this but it's not a
+ * massive downside. At some point in the future I'd like to improve the
+ * dynamic updating, but this will do for now.
+ * */
+ if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
+ t300rs_stop_effect(t300rs, state);
+ }
+
+ level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;
+ duration = effect.replay.length;
+
+ le_level = cpu_to_le16(level);
+ le_offset = cpu_to_le16(effect.replay.delay);
+ le_duration = cpu_to_le16(duration);
+
+ send_buffer[0] = 0x60;
+ send_buffer[2] = effect.id + 1;
+ send_buffer[3] = 0x6a;
+
+ send_buffer[4] = le_level & 0xff;
+ send_buffer[5] = le_level >> 8;
+
+ t300rs_fill_envelope(send_buffer, 6, level,
+ duration, &constant.envelope);
+
+ send_buffer[15] = 0x4f;
+
+ send_buffer[16] = le_duration & 0xff;
+ send_buffer[17] = le_duration >> 8;
+
+ send_buffer[20] = le_offset & 0xff;
+ send_buffer[21] = le_offset >> 8;
+
+ send_buffer[23] = 0xff;
+ send_buffer[24] = 0xff;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed uploading constant effect\n");
+ }
+
+ if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
+ t300rs_play_effect(t300rs, state);
+ }
+
+ kfree(send_buffer);
+ return ret;
+}
+
+static int t300rs_upload_ramp(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state){
+ u8 *send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_ATOMIC);
+ struct ff_effect effect = state->effect;
+ struct ff_ramp_effect ramp = state->effect.u.ramp;
+ int ret, trans;
+ u16 difference, le_difference, top, bottom, le_duration, le_offset;
+ s16 level, le_level;
+
+ if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
+ t300rs_stop_effect(t300rs, state);
+ }
+
+ top = ramp.end_level > ramp.start_level ? ramp.end_level : ramp.start_level;
+ bottom = ramp.end_level > ramp.start_level ? ramp.start_level : ramp.end_level;
+
+
+ difference = ((top - bottom) * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;
+ level = (top * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;
+
+ le_difference = cpu_to_le16(difference);
+ le_level = cpu_to_le16(level);
+ le_duration = cpu_to_le16(effect.replay.length);
+ le_offset = cpu_to_le16(effect.replay.delay);
+
+ send_buffer[0] = 0x60;
+ send_buffer[1] = effect.id + 1;
+ send_buffer[2] = 0x6b;
+
+ send_buffer[3] = le_difference & 0xff;
+ send_buffer[4] = le_difference >> 8;
+
+ send_buffer[5] = le_level & 0xff;
+ send_buffer[6] = le_level >> 8;
+
+ send_buffer[9] = le_duration & 0xff;
+ send_buffer[10] = le_duration >> 8;
+
+ send_buffer[12] = 0x80;
+
+ t300rs_fill_envelope(send_buffer, 14, level,
+ effect.replay.length, &ramp.envelope);
+
+ send_buffer[22] = ramp.end_level > ramp.start_level ? 0x04 : 0x05;
+ send_buffer[23] = 0x4f;
+
+ send_buffer[24] = le_duration & 0xff;
+ send_buffer[25] = le_duration >> 8;
+
+ send_buffer[28] = le_offset & 0xff;
+ send_buffer[29] = le_offset >> 8;
+
+ send_buffer[31] = 0xff;
+ send_buffer[32] = 0xff;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed uploading ramp");
+ }
+
+ if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
+ t300rs_play_effect(t300rs, state);
+ }
+
+ kfree(send_buffer);
+ return ret;
+}
+
+static int t300rs_upload_spring(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state){
+ u8 *send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_ATOMIC);
+ struct ff_effect effect = state->effect;
+ /* we only care about the first axis */
+ struct ff_condition_effect spring = state->effect.u.condition[0];
+ int ret, trans;
+ u16 le_right_coeff, le_left_coeff, le_deadband_right, le_deadband_left,
+ le_duration, le_offset;
+
+ if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
+ t300rs_stop_effect(t300rs, state);
+ }
+
+ send_buffer[0] = 0x60;
+ send_buffer[2] = effect.id + 1;
+ send_buffer[3] = 0x64;
+
+ le_right_coeff = cpu_to_le16(spring.right_coeff);
+ le_left_coeff = cpu_to_le16(spring.left_coeff);
+
+ le_deadband_right = cpu_to_le16(0xfffe - spring.deadband - spring.center);
+ le_deadband_left = cpu_to_le16(0xfffe - spring.deadband + spring.center);
+
+ le_duration = cpu_to_le16(effect.replay.length);
+ le_offset = cpu_to_le16(effect.replay.delay);
+
+ send_buffer[4] = le_right_coeff & 0xff;
+ send_buffer[5] = le_right_coeff >> 8;
+
+ send_buffer[6] = le_left_coeff & 0xff;
+ send_buffer[7] = le_left_coeff >> 8;
+
+ send_buffer[8] = le_deadband_right & 0xff;
+ send_buffer[9] = le_deadband_right >> 8;
+
+ send_buffer[10] = le_deadband_left & 0xff;
+ send_buffer[11] = le_deadband_left >> 8;
+
+ memcpy(&send_buffer[12], spring_values, ARRAY_SIZE(spring_values));
+ send_buffer[29] = 0x4f;
+
+ send_buffer[30] = le_duration & 0xff;
+ send_buffer[31] = le_duration >> 8;
+
+ send_buffer[34] = le_offset & 0xff;
+ send_buffer[35] = le_offset >> 8;
+
+ send_buffer[37] = 0xff;
+ send_buffer[38] = 0xff;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed uploading spring\n");
+ }
+
+ if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
+ t300rs_play_effect(t300rs, state);
+ }
+
+ kfree(send_buffer);
+ return ret;
+}
+
+static int t300rs_upload_damper(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state){
+ u8 *send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_ATOMIC);
+ struct ff_effect effect = state->effect;
+ /* we only care about the first axis */
+ struct ff_condition_effect spring = state->effect.u.condition[0];
+ int ret, trans;
+ u16 le_right_coeff, le_left_coeff, le_deadband_right, le_deadband_left,
+ le_duration, le_offset;
+
+ if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
+ t300rs_stop_effect(t300rs, state);
+ }
+
+ send_buffer[0] = 0x60;
+ send_buffer[2] = effect.id + 1;
+ send_buffer[3] = 0x64;
+
+ le_right_coeff = cpu_to_le16(spring.right_coeff);
+ le_left_coeff = cpu_to_le16(spring.left_coeff);
+
+ le_deadband_right = cpu_to_le16(0xfffe - spring.deadband - spring.center);
+ le_deadband_left = cpu_to_le16(0xfffe - spring.deadband + spring.center);
+
+ le_duration = cpu_to_le16(effect.replay.length);
+ le_offset = cpu_to_le16(effect.replay.delay);
+
+ send_buffer[4] = le_right_coeff & 0xff;
+ send_buffer[5] = le_right_coeff >> 8;
+
+ send_buffer[6] = le_left_coeff & 0xff;
+ send_buffer[7] = le_left_coeff >> 8;
+
+ send_buffer[8] = le_deadband_right & 0xff;
+ send_buffer[9] = le_deadband_right >> 8;
+
+ send_buffer[10] = le_deadband_left & 0xff;
+ send_buffer[11] = le_deadband_left >> 8;
+
+ memcpy(&send_buffer[12], damper_values, ARRAY_SIZE(damper_values));
+ send_buffer[29] = 0x4f;
+
+ send_buffer[30] = le_duration & 0xff;
+ send_buffer[31] = le_duration >> 8;
+
+ send_buffer[34] = le_offset & 0xff;
+ send_buffer[35] = le_offset >> 8;
+
+ send_buffer[37] = 0xff;
+ send_buffer[38] = 0xff;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed uploading spring\n");
+ }
+
+ if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
+ t300rs_play_effect(t300rs, state);
+ }
+
+ kfree(send_buffer);
+ return ret;
+}
+
+static int t300rs_upload_periodic(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state){
+ u8 *send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_ATOMIC);
+ struct ff_effect effect = state->effect;
+ struct ff_periodic_effect periodic = state->effect.u.periodic;
+ int ret, trans;
+ u16 magnitude, le_magnitude, le_phase, le_period, le_offset, le_duration;
+ s16 le_periodic_offset;
+
+ if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
+ t300rs_stop_effect(t300rs, state);
+ }
+
+ magnitude = (periodic.magnitude * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;
+
+ le_magnitude = cpu_to_le16(magnitude);
+ le_phase = cpu_to_le16(periodic.phase);
+ le_periodic_offset = cpu_to_le16(periodic.offset);
+ le_period = cpu_to_le16(periodic.period);
+ le_offset = cpu_to_le16(effect.replay.delay);
+ le_duration = cpu_to_le16(effect.replay.length);
+
+ send_buffer[0] = 0x60;
+ send_buffer[2] = effect.id + 1;
+ send_buffer[3] = 0x6b;
+
+ send_buffer[4] = le_magnitude & 0xff;
+ send_buffer[5] = le_magnitude >> 8;
+
+ send_buffer[6] = le_phase & 0xff;
+ send_buffer[7] = le_phase >> 8;
+
+ send_buffer[8] = le_periodic_offset & 0xff;
+ send_buffer[9] = le_periodic_offset >> 8;
+
+ send_buffer[10] = le_period & 0xff;
+ send_buffer[11] = le_period >> 8;
+
+ send_buffer[13] = 0x80;
+
+ t300rs_fill_envelope(send_buffer, 14, magnitude,
+ effect.replay.length, &periodic.envelope);
+
+ send_buffer[22] = periodic.waveform - 0x57;
+ send_buffer[23] = 0x4f;
+
+ send_buffer[24] = le_duration & 0xff;
+ send_buffer[25] = le_duration >> 8;
+
+ send_buffer[27] = le_offset & 0xff;
+ send_buffer[28] = le_offset >> 8;
+
+ send_buffer[30] = 0xff;
+ send_buffer[31] = 0xff;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed uploading periodic effect");
+ }
+
+ if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
+ t300rs_play_effect(t300rs, state);
+ }
+
+ kfree(send_buffer);
+ return ret;
+}
+
+static int t300rs_upload_effect(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state){
+ switch(state->effect.type){
+ case FF_CONSTANT:
+ return t300rs_upload_constant(t300rs, state);
+ case FF_RAMP:
+ return t300rs_upload_ramp(t300rs, state);
+ case FF_SPRING:
+ return t300rs_upload_spring(t300rs, state);
+ case FF_DAMPER:
+ case FF_FRICTION:
+ case FF_INERTIA:
+ return t300rs_upload_damper(t300rs, state);
+ case FF_PERIODIC:
+ return t300rs_upload_periodic(t300rs, state);
+ default:
+ hid_err(t300rs->hdev, "invalid effect type: %x", state->effect.type);
+ return -1;
+ }
+}
+
+static int t300rs_timer_helper(struct t300rs_device_entry *t300rs){
+ struct t300rs_effect_state *state;
+ unsigned long jiffies_now = JIFFIES2MS(jiffies);
+ int max_count = 0, effect_id, ret;
+
+ for(effect_id = 0; effect_id < T300RS_MAX_EFFECTS; ++effect_id){
+
+ state = &t300rs->states[effect_id];
+
+ if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
+ if((jiffies_now - state->start_time) >= state->effect.replay.length){
+ __clear_bit(FF_EFFECT_PLAYING, &state->flags);
+
+ if(state->count){
+ __set_bit(FF_EFFECT_QUEUE_START, &state->flags);
+ }
+ }
+ }
+
+ if(test_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags)){
+ __clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);
+
+ ret = t300rs_upload_effect(t300rs, state);
+ if(ret){
+ hid_err(t300rs->hdev, "failed uploading effects");
+ return ret;
+ }
+ }
+
+ if(test_bit(FF_EFFECT_QUEUE_START, &state->flags)){
+ __clear_bit(FF_EFFECT_QUEUE_START, &state->flags);
+ __set_bit(FF_EFFECT_PLAYING, &state->flags);
+
+ ret = t300rs_play_effect(t300rs, state);
+ if(ret){
+ hid_err(t300rs->hdev, "failed starting effects\n");
+ return ret;
+ }
+
+ if(state->count){
+ state->count--;
+ }
+ }
+
+ if(test_bit(FF_EFFECT_QUEUE_STOP, &state->flags)){
+ __clear_bit(FF_EFFECT_QUEUE_STOP, &state->flags);
+ __clear_bit(FF_EFFECT_PLAYING, &state->flags);
+
+ ret = t300rs_stop_effect(t300rs, state);
+ if(ret){
+ hid_err(t300rs->hdev, "failed stopping effect\n");
+ return ret;
+ }
+ }
+
+ if(state->count > max_count){
+ max_count = state->count;
+ }
+ }
+
+ return max_count;
+}
+
+static enum hrtimer_restart t300rs_timer(struct hrtimer *t){
+ struct t300rs_device_entry *t300rs = container_of(t, struct t300rs_device_entry, hrtimer);
+ int max_count;
+
+ max_count = t300rs_timer_helper(t300rs);
+
+ if(max_count > 0){
+ hrtimer_forward_now(&t300rs->hrtimer, ms_to_ktime(timer_msecs));
+ return HRTIMER_RESTART;
+ } else {
+ return HRTIMER_NORESTART;
+ }
+}
+
+
+static int t300rs_upload(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old){
+ struct hid_device *hdev = input_get_drvdata(dev);
+ struct t300rs_device_entry *t300rs;
+ struct t300rs_effect_state *state;
+
+ t300rs = t300rs_get_device(hdev);
+
+ if(effect->type == FF_PERIODIC && effect->u.periodic.period == 0){
+ return -EINVAL;
+ }
+
+ if(effect->id > t300rs->max_id){
+ t300rs->max_id = effect->id;
+ }
+
+ state = &t300rs->states[effect->id];
+
+ spin_lock_irqsave(&t300rs->lock, t300rs->lock_flags);
+
+ state->effect = *effect;
+ __set_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);
+
+ spin_unlock_irqrestore(&t300rs->lock, t300rs->lock_flags);
+
+ return 0;
+}
+
+static int t300rs_play(struct input_dev *dev, int effect_id, int value){
+ struct hid_device *hdev = input_get_drvdata(dev);
+ struct t300rs_device_entry *t300rs;
+ struct t300rs_effect_state *state;
+
+ t300rs = t300rs_get_device(hdev);
+
+ state = &t300rs->states[effect_id];
+
+ spin_lock_irqsave(&t300rs->lock, t300rs->lock_flags);
+
+ if(value > 0){
+ if(test_bit(FF_EFFECT_QUEUE_START, &state->flags)){
+ __set_bit(FF_EFFECT_QUEUE_STOP, &state->flags);
+ } else {
+ t300rs->effects_used++;
+ }
+
+ state->count = value;
+ state->start_time = JIFFIES2MS(jiffies);
+ __set_bit(FF_EFFECT_QUEUE_START, &state->flags);
+
+ } else {
+ __set_bit(FF_EFFECT_QUEUE_STOP, &state->flags);
+ t300rs->effects_used--;
+ }
+
+ if(!hrtimer_active(&t300rs->hrtimer)){
+ hrtimer_start(&t300rs->hrtimer, ms_to_ktime(timer_msecs), HRTIMER_MODE_REL);
+ }
+
+ spin_unlock_irqrestore(&t300rs->lock, t300rs->lock_flags);
+ return 0;
+}
+
+/* we should set a default range */
+static ssize_t t300rs_range_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count){
+ struct hid_device *hdev = to_hid_device(dev);
+ struct t300rs_device_entry *t300rs;
+ u8 *send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_ATOMIC);
+ u16 range = simple_strtoul(buf, NULL, 10);
+ int ret, trans;
+
+ t300rs = t300rs_get_device(hdev);
+
+ if(range < 0x097b){
+ range = 0x097b;
+ }
+
+ range = cpu_to_le16(range);
+
+ send_buffer[0] = 0x60;
+ send_buffer[1] = 0x08;
+ send_buffer[2] = 0x11;
+ send_buffer[3] = range & 0xff;
+ send_buffer[4] = range >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(hdev, "failed sending interrupts\n");
+ return -1;
+ }
+
+ t300rs->range = range;
+ kfree(send_buffer);
+ return count;
+}
+
+static ssize_t t300rs_range_show(struct device *dev, struct device_attribute *attr,
+ char *buf){
+ struct hid_device *hdev = to_hid_device(dev);
+ struct t300rs_device_entry *t300rs;
+
+ t300rs = t300rs_get_device(hdev);
+
+ return t300rs->range;
+}
+
+static DEVICE_ATTR(range, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, t300rs_range_show, t300rs_range_store);
+
+static void t300rs_set_autocenter(struct input_dev *dev, u16 value){
+ struct hid_device *hdev = input_get_drvdata(dev);
+ u8 *send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_ATOMIC);
+ u16 le_value = cpu_to_le16(value);
+ int ret, trans;
+
+ send_buffer[0] = 0x60;
+ send_buffer[1] = 0x08;
+ send_buffer[2] = 0x03;
+
+ send_buffer[3] = le_value & 0xff;
+ send_buffer[4] = le_value >> 8;
+
+ ret = t300rs_send_int(dev, send_buffer, &trans);
+ if(ret){
+ hid_err(hdev, "failed setting autocenter");
+ }
+
+ kfree(send_buffer);
+}
+
+static void t300rs_set_gain(struct input_dev *dev, u16 gain){
+ struct hid_device *hdev = input_get_drvdata(dev);
+ u8 *send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_ATOMIC);
+ int ret, trans;
+
+ send_buffer[0] = 0x60;
+ send_buffer[1] = 0x02;
+ send_buffer[2] = SCALE_VALUE_U16(gain, 8);
+
+ ret = t300rs_send_int(dev, send_buffer, &trans);
+ if(ret){
+ hid_err(hdev, "failed setting gain\n");
+ }
+
+ kfree(send_buffer);
+}
+
+static void t300rs_destroy(struct ff_device *ff){
+ /* maybe not temp? */
+ return;
+}
+
+
+static int t300rs_open(struct input_dev *dev){
+ struct t300rs_device_entry *t300rs;
+ struct hid_device *hdev = input_get_drvdata(dev);
+ u8 *send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_ATOMIC);
+ int ret, trans;
+
+ t300rs = t300rs_get_device(hdev);
+
+ send_buffer[0] = 0x60;
+ send_buffer[1] = 0x01;
+ send_buffer[2] = 0x04;
+
+ ret = t300rs_send_int(dev, send_buffer, &trans);
+ if(ret){
+ hid_err(hdev, "failed sending interrupts\n");
+ goto err;
+ }
+ memset(send_buffer, 0, T300RS_BUFFER_LENGTH);
+
+ send_buffer[0] = 0x60;
+ send_buffer[1] = 0x12;
+ send_buffer[2] = 0xbf;
+ send_buffer[3] = 0x04;
+ send_buffer[6] = 0x03;
+ send_buffer[7] = 0xb7;
+ send_buffer[8] = 0x1e;
+
+ ret = t300rs_send_int(dev, send_buffer, &trans);
+ if(ret){
+ hid_err(hdev, "failed sending interrupts\n");
+ goto err;
+ }
+ memset(send_buffer, 0, T300RS_BUFFER_LENGTH);
+
+ send_buffer[0] = 0x60;
+ send_buffer[1] = 0x01;
+ send_buffer[2] = 0x05;
+
+ ret = t300rs_send_int(dev, send_buffer, &trans);
+ if(ret){
+ hid_err(hdev, "failed sending interrupts\n");
+ goto err;
+ }
+
+err:
+ kfree(send_buffer);
+ return t300rs->open(dev);
+}
+
+static void t300rs_close(struct input_dev *dev){
+ int ret, trans;
+ struct hid_device *hdev = input_get_drvdata(dev);
+ struct t300rs_device_entry *t300rs;
+ u8 *send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_ATOMIC);
+
+ t300rs = t300rs_get_device(hdev);
+
+ send_buffer[0] = 0x60;
+ send_buffer[1] = 0x01;
+
+ ret = t300rs_send_int(dev, send_buffer, &trans);
+ if(ret){
+ hid_err(hdev, "failed sending interrupts\n");
+ goto err;
+ }
+err:
+ kfree(send_buffer);
+ t300rs->close(dev);
+ return;
+}
+
+int t300rs_init(struct hid_device *hdev, const signed short *ff_bits){
+ struct t300rs_device_entry *t300rs;
+ struct t300rs_data *drv_data;
+ struct list_head *report_list;
+ struct hid_input *hidinput = list_entry(hdev->inputs.next,
+ struct hid_input, list);
+ struct input_dev *input_dev = hidinput->input;
+ struct device *dev = &hdev->dev;
+ struct usb_interface *usbif = to_usb_interface(dev->parent);
+ struct usb_device *usbdev = interface_to_usbdev(usbif);
+ struct hid_report *report;
+ struct ff_device *ff;
+ char range[10] = "54000"; /* approx 900 degress */
+ int i, ret;
+
+ drv_data = hid_get_drvdata(hdev);
+ if(!drv_data){
+ hid_err(hdev, "private driver data not allocated\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ t300rs = kzalloc(sizeof(struct t300rs_device_entry), GFP_ATOMIC);
+ if(!t300rs){
+ hid_err(hdev, "device entry could not be created\n");
+ ret = -ENOMEM;
+ goto t300rs_err;
+ }
+
+ t300rs->input_dev = input_dev;
+ t300rs->hdev = hdev;
+ t300rs->usbdev = usbdev;
+ t300rs->usbif = usbif;
+ t300rs->max_id = 0;
+ t300rs->states = kmalloc(sizeof(struct t300rs_effect_state) * 0x60, GFP_ATOMIC);
+
+ if(!t300rs->states){
+ hid_err(hdev, "effect states could not be created\n");
+ ret = -ENOMEM;
+ goto states_err;
+ }
+
+ spin_lock_init(&t300rs->lock);
+
+ drv_data->device_props = t300rs;
+
+ report_list = &hdev->report_enum[HID_OUTPUT_REPORT].report_list;
+ list_for_each_entry(report, report_list, list){
+ int fieldnum;
+
+ for(fieldnum = 0; fieldnum < report->maxfield; ++fieldnum){
+ struct hid_field *field = report->field[fieldnum];
+
+ if(field->maxusage <= 0){
+ continue;
+ }
+
+ switch(field->usage[0].hid){
+ case 0xff00000a:
+ if(field->report_count < 2){
+ hid_warn(hdev, "ignoring FF field with report_count < 2\n");
+ continue;
+ }
+
+ if(field->logical_maximum == field->logical_minimum){
+ hid_warn(hdev, "ignoring FF field with l_max == l_min");
+ continue;
+ }
+
+ if(t300rs->report && t300rs->report != report){
+ hid_warn(hdev, "ignoring FF field in other report\n");
+ continue;
+ }
+
+ if(t300rs->ff_field && t300rs->ff_field != field){
+ hid_warn(hdev, "ignoring duplicate FF field\n");
+ continue;
+ }
+
+ t300rs->report = report;
+ t300rs->ff_field = field;
+
+ for(i = 0; ff_bits[i] >= 0; ++i){
+ set_bit(ff_bits[i], input_dev->ffbit);
+ }
+
+ break;
+
+ default:
+ hid_warn(hdev, "ignoring unknown output usage\n");
+ continue;
+ }
+ }
+ }
+
+ if(!t300rs->report){
+ hid_err(hdev, "can't find FF field in output reports\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ ret = input_ff_create(input_dev, T300RS_MAX_EFFECTS);
+ if(ret){
+ hid_err(hdev, "could not create input_ff\n");
+ goto out;
+ }
+
+ ff = input_dev->ff;
+ ff->upload = t300rs_upload;
+ ff->playback = t300rs_play;
+ ff->set_gain = t300rs_set_gain;
+ ff->set_autocenter = t300rs_set_autocenter;
+ ff->destroy = t300rs_destroy;
+
+ t300rs->open = input_dev->open;
+ t300rs->close = input_dev->close;
+
+ input_dev->open = t300rs_open;
+ input_dev->close = t300rs_close;
+
+ ret = device_create_file(&hdev->dev, &dev_attr_range);
+ if(ret){
+ hid_warn(hdev, "unable to create sysfs interface for range\n");
+ goto out;
+ }
+
+
+ hrtimer_init(&t300rs->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ t300rs->hrtimer.function = t300rs_timer;
+
+ spin_unlock_irqrestore(&lock, lock_flags);
+
+ t300rs_range_store(dev, &dev_attr_range, range, 10);
+ t300rs_set_gain(input_dev, 0xffff);
+
+ hid_info(hdev, "force feedback for T300RS\n");
+ return 0;
+
+out:
+ kfree(t300rs->states);
+states_err:
+ kfree(t300rs);
+t300rs_err:
+ kfree(drv_data);
+err:
+ hid_err(hdev, "failed creating force feedback device\n");
+ return ret;
+
+}
+
+static int t300rs_probe(struct hid_device *hdev, const struct hid_device_id *id){
+ int ret;
+ struct t300rs_data *drv_data;
+
+ spin_lock_init(&lock);
+ spin_lock_irqsave(&lock, lock_flags);
+
+ drv_data = kzalloc(sizeof(struct t300rs_data), GFP_ATOMIC);
+ if(!drv_data){
+ hid_err(hdev, "out of memory\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ drv_data->quirks = id->driver_data;
+ hid_set_drvdata(hdev, (void*)drv_data);
+
+ ret = hid_parse(hdev);
+ if(ret){
+ hid_err(hdev, "parse failed\n");
+ goto err;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+ if(ret){
+ hid_err(hdev, "hw start failed\n");
+ goto err;
+ }
+
+ ret = t300rs_init(hdev, (void*)id->driver_data);
+ if(ret){
+ hid_err(hdev, "t300rs_init failed\n");
+ goto err;
+ }
+ return 0;
+err:
+ kfree(drv_data);
+ spin_unlock_irqrestore(&lock, lock_flags);
+ return ret;
+}
+
+static void t300rs_remove(struct hid_device *hdev){
+ struct t300rs_device_entry *t300rs;
+ struct t300rs_data *drv_data;
+
+ device_remove_file(&hdev->dev, &dev_attr_range);
+
+ drv_data = hid_get_drvdata(hdev);
+ t300rs = t300rs_get_device(hdev);
+
+ hrtimer_cancel(&t300rs->hrtimer);
+
+ hid_hw_stop(hdev);
+ kfree(t300rs->states);
+ kfree(drv_data);
+ kfree(t300rs);
+
+ return;
+}
+
+static __u8 *t300rs_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize){
+ rdesc = t300rs_rdesc_fixed;
+ *rsize = sizeof(t300rs_rdesc_fixed);
+ return rdesc;
+}
+
+static const struct hid_device_id t300rs_devices[] = {
+ {HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb66e),
+ .driver_data = (unsigned long)t300rs_ff_effects},
+ {}
+};
+MODULE_DEVICE_TABLE(hid, t300rs_devices);
+
+static struct hid_driver t300rs_driver = {
+ .name = "t300rs",
+ .id_table = t300rs_devices,
+ .probe = t300rs_probe,
+ .remove = t300rs_remove,
+ .report_fixup = t300rs_report_fixup,
+};
+module_hid_driver(t300rs_driver);
+
+MODULE_LICENSE("GPL");