# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.485 -> 1.486 # drivers/usb/input/hid-lg3dff.c 1.1 -> (deleted) # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/07/26 greg@kroah.com 1.486 # USB: deleted hid-lg3dff.c as it's no longer needed. # -------------------------------------------- # diff -Nru a/drivers/usb/input/hid-lg3dff.c b/drivers/usb/input/hid-lg3dff.c --- a/drivers/usb/input/hid-lg3dff.c Fri Jul 26 13:47:14 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,444 +0,0 @@ -/* - * $$ - * - * Force feedback support for hid-compliant devices of the Logitech *3D family - * - * Copyright (c) 2002 Johann Deneux - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so by - * e-mail - mail your message to - */ - -#include -#include - -#define DEBUG -#include - -#include - -#include "hid.h" -#include "fixp-arith.h" - -#define RUN_AT(t) (jiffies + (t)) - -/* Periodicity of the update */ -#define PERIOD (HZ/10) - -/* Effect status: lg3d_effect::flags */ -#define EFFECT_STARTED 0 /* Effect is going to play after some time - (ff_replay.delay) */ -#define EFFECT_PLAYING 1 /* Effect is being played */ -#define EFFECT_USED 2 - -/* Check that the current process can access an effect */ -#define CHECK_OWNERSHIP(i, l) \ - (i>=0 && ieffects[i].flags) \ - && (current->pid == 0 \ - || l->effects[i].owner == current->pid)) - -#define N_EFFECTS 8 - -struct lg3d_effect { - pid_t owner; - - struct ff_effect effect; /* Description of the effect */ - - unsigned int count; /* Number of times left to play */ - unsigned long flags[1]; - - unsigned long started_at; /* When the effect started to play */ -}; - -// For lg3d_device::flags -#define DEVICE_USB_XMIT 0 /* An URB is being sent */ -#define DEVICE_CLOSING 1 /* The driver is being unitialised */ - -struct lg3d_device { - struct hid_device* hid; - - struct urb* urbffout; /* Output URB used to send ff commands */ - struct usb_ctrlrequest ffcr; /* ff commands use control URBs */ - char buf[8]; - - struct lg3d_effect effects[N_EFFECTS]; - spinlock_t lock; /* device-level lock. Having locks on - a per-effect basis could be nice, but - isn't really necessary */ - struct timer_list timer; - unsigned long last_time; /* Last time the timer handler was - executed */ - - unsigned long flags[1]; /* Contains various information about the - state of the driver for this device */ -}; - -static void hid_lg3d_ctrl_out(struct urb *urb); -static void hid_lg3d_exit(struct hid_device* hid); -static int hid_lg3d_event(struct hid_device *hid, struct input_dev *input, - unsigned int type, unsigned int code, int value); -static int hid_lg3d_flush(struct input_dev *input, struct file *file); -static int hid_lg3d_upload_effect(struct input_dev *input, - struct ff_effect *effect); -static int hid_lg3d_erase(struct input_dev *input, int id); -static void hid_lg3d_timer(unsigned long timer_data); - - -int hid_lg3d_init(struct hid_device* hid) -{ - struct lg3d_device *private; - - /* Private data */ - private = kmalloc(sizeof(struct lg3d_device), GFP_KERNEL); - if (!private) return -1; - - memset(private, 0, sizeof(struct lg3d_device)); - - hid->ff_private = private; - - private->hid = hid; - spin_lock_init(&private->lock); - - /* Timer for the periodic update task */ - init_timer(&private->timer); - private->timer.data = (unsigned long)private; - private->timer.function = hid_lg3d_timer; - - /* Event and exit callbacks */ - hid->ff_exit = hid_lg3d_exit; - hid->ff_event = hid_lg3d_event; - - /* USB init */ - if (!(private->urbffout = usb_alloc_urb(0, GFP_KERNEL))) { - kfree(hid->ff_private); - return -1; - } - - usb_fill_control_urb(private->urbffout, hid->dev, 0, - (void*) &private->ffcr, private->buf, 8, - hid_lg3d_ctrl_out, hid); - dbg("Created ff output control urb"); - - /* Input init */ - hid->input.upload_effect = hid_lg3d_upload_effect; - hid->input.flush = hid_lg3d_flush; - set_bit(FF_CONSTANT, hid->input.ffbit); - set_bit(EV_FF, hid->input.evbit); - hid->input.ff_effects_max = N_EFFECTS; - - printk(KERN_INFO "Force feedback for Logitech *3D devices by Johann Deneux \n"); - - /* Start the update task */ - private->timer.expires = RUN_AT(PERIOD); - add_timer(&private->timer); /*TODO: only run the timer when at least - one effect is playing */ - - return 0; -} - -static void hid_lg3d_exit(struct hid_device* hid) -{ - struct lg3d_device *lg3d = hid->ff_private; - unsigned long flags; - - spin_lock_irqsave(&lg3d->lock, flags); - set_bit(DEVICE_CLOSING, lg3d->flags); - spin_unlock_irqrestore(&lg3d->lock, flags); - - del_timer_sync(&lg3d->timer); - - if (lg3d->urbffout) { - usb_unlink_urb(lg3d->urbffout); - usb_free_urb(lg3d->urbffout); - } - - kfree(lg3d); -} - -static int hid_lg3d_event(struct hid_device *hid, struct input_dev* input, - unsigned int type, unsigned int code, int value) -{ - struct lg3d_device *lg3d = hid->ff_private; - struct lg3d_effect *effect = lg3d->effects + code; - unsigned long flags; - - if (type != EV_FF) return -EINVAL; - if (!CHECK_OWNERSHIP(code, lg3d)) return -EACCES; - if (value < 0) return -EINVAL; - - spin_lock_irqsave(&lg3d->lock, flags); - - if (value > 0) { - if (test_bit(EFFECT_STARTED, effect->flags)) { - spin_unlock_irqrestore(&lg3d->lock, flags); - return -EBUSY; - } - if (test_bit(EFFECT_PLAYING, effect->flags)) { - spin_unlock_irqrestore(&lg3d->lock, flags); - return -EBUSY; - } - - effect->count = value; - - if (effect->effect.replay.delay) { - set_bit(EFFECT_STARTED, effect->flags); - } else { - set_bit(EFFECT_PLAYING, effect->flags); - } - effect->started_at = jiffies; - } - else { /* value == 0 */ - clear_bit(EFFECT_STARTED, effect->flags); - clear_bit(EFFECT_PLAYING, effect->flags); - } - - spin_unlock_irqrestore(&lg3d->lock, flags); - - return 0; -} - -/* Erase all effects this process owns */ -static int hid_lg3d_flush(struct input_dev *dev, struct file *file) -{ - struct hid_device *hid = dev->private; - struct lg3d_device *lg3d = hid->ff_private; - int i; - - for (i=0; iff_effects_max; ++i) { - - /*NOTE: no need to lock here. The only times EFFECT_USED is - modified is when effects are uploaded or when an effect is - erased. But a process cannot close its dev/input/eventX fd - and perform ioctls on the same fd all at the same time */ - if ( current->pid == lg3d->effects[i].owner - && test_bit(EFFECT_USED, lg3d->effects[i].flags)) { - - if (hid_lg3d_erase(dev, i)) - warn("erase effect %d failed", i); - } - - } - - return 0; -} - -static int hid_lg3d_erase(struct input_dev *dev, int id) -{ - struct hid_device *hid = dev->private; - struct lg3d_device *lg3d = hid->ff_private; - unsigned long flags; - - if (!CHECK_OWNERSHIP(id, lg3d)) return -EACCES; - - spin_lock_irqsave(&lg3d->lock, flags); - lg3d->effects[id].flags[0] = 0; - spin_unlock_irqrestore(&lg3d->lock, flags); - - return 0; -} - -static int hid_lg3d_upload_effect(struct input_dev* input, - struct ff_effect* effect) -{ - struct hid_device *hid = input->private; - struct lg3d_device *lg3d = hid->ff_private; - struct lg3d_effect new; - int id; - unsigned long flags; - - dbg("ioctl upload"); - - if (!test_bit(effect->type, input->ffbit)) return -EINVAL; - - if (effect->type != FF_CONSTANT) return -EINVAL; - - spin_lock_irqsave(&lg3d->lock, flags); - - if (effect->id == -1) { - int i; - - for (i=0; ieffects[i].flags); ++i); - if (i >= N_EFFECTS) { - spin_unlock_irqrestore(&lg3d->lock, flags); - return -ENOSPC; - } - - effect->id = i; - lg3d->effects[i].owner = current->pid; - lg3d->effects[i].flags[0] = 0; - set_bit(EFFECT_USED, lg3d->effects[i].flags); - } - else if (!CHECK_OWNERSHIP(effect->id, lg3d)) { - spin_unlock_irqrestore(&lg3d->lock, flags); - return -EACCES; - } - - id = effect->id; - new = lg3d->effects[id]; - - new.effect = *effect; - new.effect.replay = effect->replay; - - if (test_bit(EFFECT_STARTED, lg3d->effects[id].flags) - || test_bit(EFFECT_STARTED, lg3d->effects[id].flags)) { - - /* Changing replay parameters is not allowed (for the time - being) */ - if (new.effect.replay.delay != lg3d->effects[id].effect.replay.delay - || new.effect.replay.length != lg3d->effects[id].effect.replay.length) { - spin_unlock_irqrestore(&lg3d->lock, flags); - return -ENOSYS; - } - - lg3d->effects[id] = new; - - } else { - lg3d->effects[id] = new; - } - - spin_unlock_irqrestore(&lg3d->lock, flags); - return 0; -} - -static void hid_lg3d_ctrl_out(struct urb *urb) -{ - struct hid_device *hid = urb->context; - struct lg3d_device *lg3d = hid->ff_private; - unsigned long flags; - - spin_lock_irqsave(&lg3d->lock, flags); - - if (urb->status) - warn("hid_irq_ffout status %d received", urb->status); - clear_bit(DEVICE_USB_XMIT, lg3d->flags); - dbg("xmit = 0"); - - spin_unlock_irqrestore(&lg3d->lock, flags); -} - -static void hid_lg3d_timer(unsigned long timer_data) -{ - struct lg3d_device *lg3d = (struct lg3d_device*)timer_data; - struct hid_device *hid = lg3d->hid; - unsigned long flags; - int x, y; - int i; - int err; - - spin_lock_irqsave(&lg3d->lock, flags); - - if (test_bit(DEVICE_USB_XMIT, lg3d->flags)) { - if (lg3d->urbffout->status != -EINPROGRESS) { - warn("xmit *not* in progress"); - } - else { - dbg("xmit in progress"); - } - - spin_unlock_irqrestore(&lg3d->lock, flags); - - lg3d->timer.expires = RUN_AT(PERIOD); - add_timer(&lg3d->timer); - - return; - } - - x = 0x7f; - y = 0x7f; - - for (i=0; ieffects +i; - - if (test_bit(EFFECT_PLAYING, effect->flags)) { - - if (effect->effect.type == FF_CONSTANT) { - //TODO: handle envelopes - int degrees = effect->effect.direction * 360 >> 16; - x += fixp_mult(fixp_sin(degrees), - fixp_new16(effect->effect.u.constant.level)); - y += fixp_mult(-fixp_cos(degrees), - fixp_new16(effect->effect.u.constant.level)); - } - - /* One run of the effect is finished playing */ - if (time_after(jiffies, - effect->started_at - + effect->effect.replay.delay*HZ/1000 - + effect->effect.replay.length*HZ/1000)) { - dbg("Finished playing once"); - if (--effect->count <= 0) { - dbg("Stopped"); - clear_bit(EFFECT_PLAYING, effect->flags); - } - else { - dbg("Start again"); - if (effect->effect.replay.length != 0) { - clear_bit(EFFECT_PLAYING, effect->flags); - set_bit(EFFECT_STARTED, effect->flags); - } - effect->started_at = jiffies; - } - } - - } else if (test_bit(EFFECT_STARTED, lg3d->effects[i].flags)) { - dbg("Started"); - /* Check if we should start playing the effect */ - if (time_after(jiffies, - lg3d->effects[i].started_at - + lg3d->effects[i].effect.replay.delay*HZ/1000)) { - dbg("Now playing"); - clear_bit(EFFECT_STARTED, lg3d->effects[i].flags); - set_bit(EFFECT_PLAYING, lg3d->effects[i].flags); - } - } - } - - if (x < 0) x = 0; - if (x > 0xff) x = 0xff; - if (y < 0) y = 0; - if (y > 0xff) y = 0xff; - - lg3d->urbffout->pipe = usb_sndctrlpipe(hid->dev, 0); - lg3d->ffcr.bRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE; - lg3d->urbffout->transfer_buffer_length = lg3d->ffcr.wLength = 8; - lg3d->ffcr.bRequest = 9; - lg3d->ffcr.wValue = 0x0200; /*NOTE: Potential problem with - little/big endian */ - lg3d->ffcr.wIndex = 0; - - lg3d->urbffout->dev = hid->dev; - - lg3d->buf[0] = 0x51; - lg3d->buf[1] = 0x08; - lg3d->buf[2] = x; - lg3d->buf[3] = y; - - if ((err=usb_submit_urb(lg3d->urbffout, GFP_ATOMIC))) - warn("usb_submit_urb returned %d", err); - else - set_bit(DEVICE_USB_XMIT, lg3d->flags); - - if (!test_bit(DEVICE_CLOSING, lg3d->flags)) { - lg3d->timer.expires = RUN_AT(PERIOD); - add_timer(&lg3d->timer); - } - - spin_unlock_irqrestore(&lg3d->lock, flags); -}