From: Rodrigo D. <rda...@us...> - 2002-04-23 00:59:28
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/usb/input In directory usw-pr-cvs1:/tmp/cvs-serv12898 Modified Files: hid-input.c hid.h pid.c pid.h Log Message: PID update Index: hid-input.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/usb/input/hid-input.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- hid-input.c 16 Apr 2002 17:41:51 -0000 1.1 +++ hid-input.c 23 Apr 2002 00:59:25 -0000 1.2 @@ -299,6 +299,9 @@ case 0x7e: usage->code = FF_GAIN; break; case 0x83: /* Simultaneous Effects Max */ input->ff_effects_max = (field->value[0]); +#ifdef DEBUG + printk("Maximum Effects - %d",input->ff_effects_max); +#endif break; case 0x98: /* Device Control */ usage->code = FF_AUTOCENTER; break; @@ -307,6 +310,9 @@ bit = input->keybit; usage->type = EV_KEY; max = KEY_MAX; +#ifdef DEBUG + printk("Safety Switch Report\n"); +#endif break; // case 0x94: /* Effect Playing */ // usage->code = FF_STATUS_PLAYING; @@ -326,6 +332,10 @@ break; default: unknown: +#ifdef DEBUG +// Temporary!! + resolv_usage(usage->hid); +#endif if (field->report_size == 1) { @@ -417,6 +427,7 @@ if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */ input->ff_effects_max = value; + printk("Maximum Effects - %d",input->ff_effects_max); return; } if (usage->hid == (HID_UP_PID | 0x7fUL)) { Index: hid.h =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/usb/input/hid.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- hid.h 16 Apr 2002 17:41:51 -0000 1.1 +++ hid.h 23 Apr 2002 00:59:25 -0000 1.2 @@ -418,6 +418,7 @@ int hid_set_field(struct hid_field *, unsigned, __s32); void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir); void hid_init_reports(struct hid_device *hid); +int hid_find_report_by_usage(struct hid_device *hid, __u32 wanted_usage, struct hid_report **report, int type); #ifdef CONFIG_HID_FF Index: pid.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/usb/input/pid.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- pid.c 16 Apr 2002 17:41:51 -0000 1.1 +++ pid.c 23 Apr 2002 00:59:25 -0000 1.2 @@ -39,11 +39,9 @@ #define DEBUG -/* MODULE_AUTHOR("Rodrigo Damazio <rda...@ls...>"); MODULE_DESCRIPTION("USB PID(Physical Interface Device) Driver"); MODULE_LICENSE("GPL"); -*/ #define CHECK_OWNERSHIP(i, hid_pid) \ ((i) < FF_EFFECTS_MAX && i >= 0 && \ @@ -54,26 +52,40 @@ /* Called when a transfer is completed */ static void hid_pid_ctrl_out(struct urb *u) { +#ifdef DEBUG + printk("hid_pid_ctrl_out - Transfer Completed\n"); +#endif } static void hid_pid_exit(struct hid_device* hid) { + struct hid_ff_pid *private = hid->ff_private; + + if (private->urbffout) { + usb_unlink_urb(private->urbffout); + usb_free_urb(private->urbffout); + } } static int pid_upload_periodic(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) { - return -ENOMEM; + + printk("Requested periodic force upload\n"); + return 0; } static int pid_upload_constant(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) { - return -ENOMEM; + printk("Requested constant force upload\n"); + return 0; } static int pid_upload_condition(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) { - return -ENOMEM; + printk("Requested Condition force upload\n"); + return 0; } static int pid_upload_ramp(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) { - return -ENOMEM; + printk("Request ramp force upload\n"); + return 0; } static int hid_pid_event(struct hid_device *hid, struct input_dev *input, @@ -91,36 +103,116 @@ return 0; } -static int hid_pid_flush(struct input_dev *input, struct file *file) +/* Lock must be held by caller */ +static void hid_pid_ctrl_playback(struct hid_device *hid, + struct hid_pid_effect *effect, int play) { - return 0; + if (play) { + set_bit(FF_PID_FLAGS_PLAYING, &effect->flags); + + } else { + clear_bit(FF_PID_FLAGS_PLAYING, &effect->flags); + } } + +static int hid_pid_erase(struct input_dev *dev, int id) +{ + struct hid_device *hid = dev->private; + struct hid_field* field; + struct hid_report* report; + struct hid_ff_pid *pid = hid->ff_private; + unsigned long flags; + unsigned wanted_report = HID_UP_PID | FF_PID_USAGE_BLOCK_FREE; /* PID Block Free Report */ + int ret; + + if (!CHECK_OWNERSHIP(id, pid)) return -EACCES; + + /* Find report */ + ret = hid_find_report_by_usage(hid, wanted_report, &report, HID_OUTPUT_REPORT); + if(!ret) { + printk("Couldn't find report\n"); + return ret; + } + + /* Find field */ + field = (struct hid_field *) kmalloc(sizeof(struct hid_field), GFP_KERNEL); + ret = hid_set_field(field, ret, pid->effects[id].device_id); + if(!ret) { + printk("Couldn't set field\n"); + return ret; + } + + hid_submit_report(hid, report, USB_DIR_OUT); + + spin_lock_irqsave(&pid->lock, flags); + hid_pid_ctrl_playback(hid, pid->effects + id, 0); + pid->effects[id].flags = 0; + spin_unlock_irqrestore(&pid->lock, flags); + + return ret; +} + +/* Erase all effects this process owns */ +static int hid_pid_flush(struct input_dev *dev, struct file *file) +{ + struct hid_device *hid = dev->private; + struct hid_ff_pid *pid = hid->ff_private; + int 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 */ + for (i=0; i<dev->ff_effects_max; ++i) + if ( current->pid == pid->effects[i].owner + && test_bit(FF_PID_FLAGS_USED, &pid->effects[i].flags)) + if (hid_pid_erase(dev, i)) + warn("erase effect %d failed", i); + + return 0; +} + + static int hid_pid_upload_effect(struct input_dev *dev, struct ff_effect *effect) { struct hid_ff_pid* pid_private = (struct hid_ff_pid*)(dev->private); - int id; int ret; int is_update; + int flags=0; #ifdef DEBUG - printk("Upload effect called: effect_type=%x\n",effect->type); + printk("Upload effect called: effect_type=%x\n",effect->type); #endif /* Check this effect type is supported by this device */ - if (!test_bit(effect->type, dev->ffbit)) + if (!test_bit(effect->type, dev->ffbit)) { +#ifdef DEBUG + printk("Invalid kind of effect requested.\n"); +#endif return -EINVAL; + } /* * If we want to create a new effect, get a free id */ if (effect->id == -1) { + int id=0; - for (id=0; id < FF_EFFECTS_MAX; ++id) - if (!test_and_set_bit(FF_PID_FLAGS_USED, &pid_private->effects[id].flags)) break; + // Spinlock so we don`t get a race condition when choosing IDs + spin_lock_irqsave(&pid_private->lock,flags); - if ( id == FF_EFFECTS_MAX || id >= dev->ff_effects_max) + while(id < FF_EFFECTS_MAX) + if (!test_and_set_bit(FF_PID_FLAGS_USED, &pid_private->effects[id++].flags)) + break; + + if ( id == FF_EFFECTS_MAX) { +// TEMP - We need to get ff_effects_max correctly first: || id >= dev->ff_effects_max) { +#ifdef DEBUG + printk("Not enough device memory\n"); +#endif return -ENOMEM; + } effect->id = id; #ifdef DEBUG @@ -128,13 +220,14 @@ #endif pid_private->effects[id].owner = current->pid; pid_private->effects[id].flags = (1<<FF_PID_FLAGS_USED); + spin_unlock_irqrestore(&pid_private->lock,flags); is_update = FF_PID_FALSE; } else { /* We want to update an effect */ if (!CHECK_OWNERSHIP(effect->id, pid_private)) return -EACCES; - + /* Parameter type cannot be updated */ if (effect->type != pid_private->effects[effect->id].effect.type) return -EINVAL; @@ -171,14 +264,16 @@ break; default: +#ifdef DEBUG + printk("Invalid type of effect requested - %x.\n", effect->type); +#endif return -EINVAL; } - if (ret == 0) { - /* A packet was sent, forbid new updates until we are notified - * that the packet was updated - */ + /* If a packet was sent, forbid new updates until we are notified + * that the packet was updated + */ + if (ret == 0) set_bit(FF_PID_FLAGS_UPDATING, &pid_private->effects[effect->id].flags); - } pid_private->effects[effect->id].effect = *effect; return ret; } @@ -187,11 +282,13 @@ { struct hid_ff_pid *private; - private = hid->input.private = hid->ff_private = kmalloc(sizeof(struct hid_ff_pid), GFP_KERNEL); + private = hid->ff_private = kmalloc(sizeof(struct hid_ff_pid), GFP_KERNEL); if (!private) return -1; memset(private,0,sizeof(struct hid_ff_pid)); - + + hid->ff_private = private; /* 'cause memset can move the block away */ + private->hid = hid; hid->ff_exit = hid_pid_exit; @@ -206,17 +303,15 @@ usb_fill_control_urb(private->urbffout, hid->dev,0,(void *) &private->ffcr,private->ctrl_buffer,8,hid_pid_ctrl_out,hid); hid->input.upload_effect = hid_pid_upload_effect; hid->input.flush = hid_pid_flush; + hid->input.ff_effects_max = 8; // A random default set_bit(EV_FF, hid->input.evbit); set_bit(EV_FF_STATUS, hid->input.evbit); - /* Retrieve specific device capabilities(types of effects it can play, etc.) */ - -// set_bit(FF_CONSTANT, hid->input.ffbit); + spin_lock_init(&private->lock); printk(KERN_INFO "Force feedback driver for PID devices by Rodrigo Damazio <rda...@ls...>.\n"); - return 0; - + return 0; } static int __init hid_pid_modinit(void) @@ -229,7 +324,7 @@ } -//module_init(hid_pid_modinit); -//module_exit(hid_pid_modexit); +module_init(hid_pid_modinit); +module_exit(hid_pid_modexit); Index: pid.h =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/usb/input/pid.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- pid.h 16 Apr 2002 17:41:51 -0000 1.1 +++ pid.h 23 Apr 2002 00:59:25 -0000 1.2 @@ -25,8 +25,9 @@ #define FF_EFFECTS_MAX 64 -#define FF_PID_FLAGS_USED 1 -#define FF_PID_FLAGS_UPDATING 2 +#define FF_PID_FLAGS_USED 1 /* If the effect exists */ +#define FF_PID_FLAGS_UPDATING 2 /* If the effect is being updated */ +#define FF_PID_FLAGS_PLAYING 3 /* If the effect is currently being played */ #define FF_PID_FALSE 0 #define FF_PID_TRUE 1 @@ -34,19 +35,28 @@ struct hid_pid_effect { unsigned int flags; pid_t owner; + unsigned int device_id; // The device-assigned ID struct ff_effect effect; }; struct hid_ff_pid { struct hid_device *hid; + unsigned long int gain; struct urb *urbffout; struct usb_ctrlrequest ffcr; + spinlock_t lock; char ctrl_buffer[8]; - unsigned long int gain; - unsigned int max_effects; - struct hid_pid_effect effects[FF_EFFECTS_MAX]; }; + +/* + * Constants from the PID usage table (still far from complete) + */ + +#define FF_PID_USAGE_BLOCK_LOAD 0x89UL +#define FF_PID_USAGE_BLOCK_FREE 0x90UL +#define FF_PID_USAGE_NEW_EFFECT 0xABUL +#define FF_PID_USAGE_POOL_REPORT 0x7FUL |