|
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
|