Path: blob/master/drivers/input/joystick/iforce/iforce-main.c
15115 views
/*1* Copyright (c) 2000-2002 Vojtech Pavlik <[email protected]>2* Copyright (c) 2001-2002, 2007 Johann Deneux <[email protected]>3*4* USB/RS232 I-Force joysticks and wheels.5*/67/*8* This program is free software; you can redistribute it and/or modify9* it under the terms of the GNU General Public License as published by10* the Free Software Foundation; either version 2 of the License, or11* (at your option) any later version.12*13* This program is distributed in the hope that it will be useful,14* but WITHOUT ANY WARRANTY; without even the implied warranty of15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16* GNU General Public License for more details.17*18* You should have received a copy of the GNU General Public License19* along with this program; if not, write to the Free Software20* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA21*22* Should you need to contact me, the author, you can do so either by23* e-mail - mail your message to <[email protected]>, or by paper mail:24* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic25*/2627#include "iforce.h"2829MODULE_AUTHOR("Vojtech Pavlik <[email protected]>, Johann Deneux <[email protected]>");30MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");31MODULE_LICENSE("GPL");3233static signed short btn_joystick[] =34{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,35BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 };3637static signed short btn_avb_pegasus[] =38{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,39BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 };4041static signed short btn_wheel[] =42{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,43BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 };4445static signed short btn_avb_tw[] =46{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE,47BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 };4849static signed short btn_avb_wheel[] =50{ BTN_GEAR_DOWN, BTN_GEAR_UP, BTN_BASE, BTN_BASE2, BTN_BASE3,51BTN_BASE4, BTN_BASE5, BTN_BASE6, -1 };5253static signed short abs_joystick[] =54{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };5556static signed short abs_joystick_rudder[] =57{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_HAT0X, ABS_HAT0Y, -1 };5859static signed short abs_avb_pegasus[] =60{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_HAT0X, ABS_HAT0Y,61ABS_HAT1X, ABS_HAT1Y, -1 };6263static signed short abs_wheel[] =64{ ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 };6566static signed short ff_iforce[] =67{ FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_DAMPER,68FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN,69FF_AUTOCENTER, -1 };7071static struct iforce_device iforce_device[] = {72{ 0x044f, 0xa01c, "Thrustmaster Motor Sport GT", btn_wheel, abs_wheel, ff_iforce },73{ 0x046d, 0xc281, "Logitech WingMan Force", btn_joystick, abs_joystick, ff_iforce },74{ 0x046d, 0xc291, "Logitech WingMan Formula Force", btn_wheel, abs_wheel, ff_iforce },75{ 0x05ef, 0x020a, "AVB Top Shot Pegasus", btn_avb_pegasus, abs_avb_pegasus, ff_iforce },76{ 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_avb_wheel, abs_wheel, ff_iforce },77{ 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel", btn_avb_tw, abs_wheel, ff_iforce }, //?78{ 0x061c, 0xc0a4, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //?79{ 0x061c, 0xc084, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce },80{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //?81{ 0x06f8, 0x0001, "Guillemot Jet Leader Force Feedback", btn_joystick, abs_joystick_rudder, ff_iforce },82{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //?83{ 0x06f8, 0xa302, "Guillemot Jet Leader 3D", btn_joystick, abs_joystick, ff_iforce }, //?84{ 0x06d6, 0x29bc, "Trust Force Feedback Race Master", btn_wheel, abs_wheel, ff_iforce },85{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }86};8788static int iforce_playback(struct input_dev *dev, int effect_id, int value)89{90struct iforce *iforce = input_get_drvdata(dev);91struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id];9293if (value > 0)94set_bit(FF_CORE_SHOULD_PLAY, core_effect->flags);95else96clear_bit(FF_CORE_SHOULD_PLAY, core_effect->flags);9798iforce_control_playback(iforce, effect_id, value);99return 0;100}101102static void iforce_set_gain(struct input_dev *dev, u16 gain)103{104struct iforce *iforce = input_get_drvdata(dev);105unsigned char data[3];106107data[0] = gain >> 9;108iforce_send_packet(iforce, FF_CMD_GAIN, data);109}110111static void iforce_set_autocenter(struct input_dev *dev, u16 magnitude)112{113struct iforce *iforce = input_get_drvdata(dev);114unsigned char data[3];115116data[0] = 0x03;117data[1] = magnitude >> 9;118iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);119120data[0] = 0x04;121data[1] = 0x01;122iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);123}124125/*126* Function called when an ioctl is performed on the event dev entry.127* It uploads an effect to the device128*/129static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)130{131struct iforce *iforce = input_get_drvdata(dev);132struct iforce_core_effect *core_effect = &iforce->core_effects[effect->id];133int ret;134135if (__test_and_set_bit(FF_CORE_IS_USED, core_effect->flags)) {136/* Check the effect is not already being updated */137if (test_bit(FF_CORE_UPDATE, core_effect->flags))138return -EAGAIN;139}140141/*142* Upload the effect143*/144switch (effect->type) {145146case FF_PERIODIC:147ret = iforce_upload_periodic(iforce, effect, old);148break;149150case FF_CONSTANT:151ret = iforce_upload_constant(iforce, effect, old);152break;153154case FF_SPRING:155case FF_DAMPER:156ret = iforce_upload_condition(iforce, effect, old);157break;158159default:160return -EINVAL;161}162163if (ret == 0) {164/* A packet was sent, forbid new updates until we are notified165* that the packet was updated166*/167set_bit(FF_CORE_UPDATE, core_effect->flags);168}169return ret;170}171172/*173* Erases an effect: it frees the effect id and mark as unused the memory174* allocated for the parameters175*/176static int iforce_erase_effect(struct input_dev *dev, int effect_id)177{178struct iforce *iforce = input_get_drvdata(dev);179struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id];180int err = 0;181182if (test_bit(FF_MOD1_IS_USED, core_effect->flags))183err = release_resource(&core_effect->mod1_chunk);184185if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags))186err = release_resource(&core_effect->mod2_chunk);187188/* TODO: remember to change that if more FF_MOD* bits are added */189core_effect->flags[0] = 0;190191return err;192}193194static int iforce_open(struct input_dev *dev)195{196struct iforce *iforce = input_get_drvdata(dev);197198switch (iforce->bus) {199#ifdef CONFIG_JOYSTICK_IFORCE_USB200case IFORCE_USB:201iforce->irq->dev = iforce->usbdev;202if (usb_submit_urb(iforce->irq, GFP_KERNEL))203return -EIO;204break;205#endif206}207208if (test_bit(EV_FF, dev->evbit)) {209/* Enable force feedback */210iforce_send_packet(iforce, FF_CMD_ENABLE, "\004");211}212213return 0;214}215216static void iforce_close(struct input_dev *dev)217{218struct iforce *iforce = input_get_drvdata(dev);219int i;220221if (test_bit(EV_FF, dev->evbit)) {222/* Check: no effects should be present in memory */223for (i = 0; i < dev->ff->max_effects; i++) {224if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) {225dev_warn(&dev->dev,226"%s: Device still owns effects\n",227__func__);228break;229}230}231232/* Disable force feedback playback */233iforce_send_packet(iforce, FF_CMD_ENABLE, "\001");234/* Wait for the command to complete */235wait_event_interruptible(iforce->wait,236!test_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags));237}238239switch (iforce->bus) {240#ifdef CONFIG_JOYSTICK_IFORCE_USB241case IFORCE_USB:242usb_kill_urb(iforce->irq);243usb_kill_urb(iforce->out);244usb_kill_urb(iforce->ctrl);245break;246#endif247#ifdef CONFIG_JOYSTICK_IFORCE_232248case IFORCE_232:249//TODO: Wait for the last packets to be sent250break;251#endif252}253}254255int iforce_init_device(struct iforce *iforce)256{257struct input_dev *input_dev;258struct ff_device *ff;259unsigned char c[] = "CEOV";260int i, error;261int ff_effects = 0;262263input_dev = input_allocate_device();264if (!input_dev)265return -ENOMEM;266267init_waitqueue_head(&iforce->wait);268spin_lock_init(&iforce->xmit_lock);269mutex_init(&iforce->mem_mutex);270iforce->xmit.buf = iforce->xmit_data;271iforce->dev = input_dev;272273/*274* Input device fields.275*/276277switch (iforce->bus) {278#ifdef CONFIG_JOYSTICK_IFORCE_USB279case IFORCE_USB:280input_dev->id.bustype = BUS_USB;281input_dev->dev.parent = &iforce->usbdev->dev;282break;283#endif284#ifdef CONFIG_JOYSTICK_IFORCE_232285case IFORCE_232:286input_dev->id.bustype = BUS_RS232;287input_dev->dev.parent = &iforce->serio->dev;288break;289#endif290}291292input_set_drvdata(input_dev, iforce);293294input_dev->name = "Unknown I-Force device";295input_dev->open = iforce_open;296input_dev->close = iforce_close;297298/*299* On-device memory allocation.300*/301302iforce->device_memory.name = "I-Force device effect memory";303iforce->device_memory.start = 0;304iforce->device_memory.end = 200;305iforce->device_memory.flags = IORESOURCE_MEM;306iforce->device_memory.parent = NULL;307iforce->device_memory.child = NULL;308iforce->device_memory.sibling = NULL;309310/*311* Wait until device ready - until it sends its first response.312*/313314for (i = 0; i < 20; i++)315if (!iforce_get_id_packet(iforce, "O"))316break;317318if (i == 20) { /* 5 seconds */319err("Timeout waiting for response from device.");320error = -ENODEV;321goto fail;322}323324/*325* Get device info.326*/327328if (!iforce_get_id_packet(iforce, "M"))329input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1];330else331dev_warn(&iforce->dev->dev, "Device does not respond to id packet M\n");332333if (!iforce_get_id_packet(iforce, "P"))334input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1];335else336dev_warn(&iforce->dev->dev, "Device does not respond to id packet P\n");337338if (!iforce_get_id_packet(iforce, "B"))339iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];340else341dev_warn(&iforce->dev->dev, "Device does not respond to id packet B\n");342343if (!iforce_get_id_packet(iforce, "N"))344ff_effects = iforce->edata[1];345else346dev_warn(&iforce->dev->dev, "Device does not respond to id packet N\n");347348/* Check if the device can store more effects than the driver can really handle */349if (ff_effects > IFORCE_EFFECTS_MAX) {350dev_warn(&iforce->dev->dev, "Limiting number of effects to %d (device reports %d)\n",351IFORCE_EFFECTS_MAX, ff_effects);352ff_effects = IFORCE_EFFECTS_MAX;353}354355/*356* Display additional info.357*/358359for (i = 0; c[i]; i++)360if (!iforce_get_id_packet(iforce, c + i))361iforce_dump_packet("info", iforce->ecmd, iforce->edata);362363/*364* Disable spring, enable force feedback.365*/366iforce_set_autocenter(input_dev, 0);367368/*369* Find appropriate device entry370*/371372for (i = 0; iforce_device[i].idvendor; i++)373if (iforce_device[i].idvendor == input_dev->id.vendor &&374iforce_device[i].idproduct == input_dev->id.product)375break;376377iforce->type = iforce_device + i;378input_dev->name = iforce->type->name;379380/*381* Set input device bitfields and ranges.382*/383384input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) |385BIT_MASK(EV_FF_STATUS);386387for (i = 0; iforce->type->btn[i] >= 0; i++)388set_bit(iforce->type->btn[i], input_dev->keybit);389set_bit(BTN_DEAD, input_dev->keybit);390391for (i = 0; iforce->type->abs[i] >= 0; i++) {392393signed short t = iforce->type->abs[i];394395switch (t) {396397case ABS_X:398case ABS_Y:399case ABS_WHEEL:400401input_set_abs_params(input_dev, t, -1920, 1920, 16, 128);402set_bit(t, input_dev->ffbit);403break;404405case ABS_THROTTLE:406case ABS_GAS:407case ABS_BRAKE:408409input_set_abs_params(input_dev, t, 0, 255, 0, 0);410break;411412case ABS_RUDDER:413414input_set_abs_params(input_dev, t, -128, 127, 0, 0);415break;416417case ABS_HAT0X:418case ABS_HAT0Y:419case ABS_HAT1X:420case ABS_HAT1Y:421422input_set_abs_params(input_dev, t, -1, 1, 0, 0);423break;424}425}426427if (ff_effects) {428429for (i = 0; iforce->type->ff[i] >= 0; i++)430set_bit(iforce->type->ff[i], input_dev->ffbit);431432error = input_ff_create(input_dev, ff_effects);433if (error)434goto fail;435436ff = input_dev->ff;437ff->upload = iforce_upload_effect;438ff->erase = iforce_erase_effect;439ff->set_gain = iforce_set_gain;440ff->set_autocenter = iforce_set_autocenter;441ff->playback = iforce_playback;442}443/*444* Register input device.445*/446447error = input_register_device(iforce->dev);448if (error)449goto fail;450451return 0;452453fail: input_free_device(input_dev);454return error;455}456457static int __init iforce_init(void)458{459int err = 0;460461#ifdef CONFIG_JOYSTICK_IFORCE_USB462err = usb_register(&iforce_usb_driver);463if (err)464return err;465#endif466#ifdef CONFIG_JOYSTICK_IFORCE_232467err = serio_register_driver(&iforce_serio_drv);468#ifdef CONFIG_JOYSTICK_IFORCE_USB469if (err)470usb_deregister(&iforce_usb_driver);471#endif472#endif473return err;474}475476static void __exit iforce_exit(void)477{478#ifdef CONFIG_JOYSTICK_IFORCE_USB479usb_deregister(&iforce_usb_driver);480#endif481#ifdef CONFIG_JOYSTICK_IFORCE_232482serio_unregister_driver(&iforce_serio_drv);483#endif484}485486module_init(iforce_init);487module_exit(iforce_exit);488489490