/* * Function called when an ioctl is performed on the event dev entry. * It uploads an effect to the device
*/ staticint iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
{ struct iforce *iforce = input_get_drvdata(dev); struct iforce_core_effect *core_effect = &iforce->core_effects[effect->id]; int ret;
if (__test_and_set_bit(FF_CORE_IS_USED, core_effect->flags)) { /* Check the effect is not already being updated */ if (test_bit(FF_CORE_UPDATE, core_effect->flags)) return -EAGAIN;
}
/* * Upload the effect
*/ switch (effect->type) { case FF_PERIODIC:
ret = iforce_upload_periodic(iforce, effect, old); break;
case FF_CONSTANT:
ret = iforce_upload_constant(iforce, effect, old); break;
case FF_SPRING: case FF_DAMPER:
ret = iforce_upload_condition(iforce, effect, old); break;
default: return -EINVAL;
}
if (ret == 0) { /* A packet was sent, forbid new updates until we are notified * that the packet was updated
*/
set_bit(FF_CORE_UPDATE, core_effect->flags);
} return ret;
}
/* * Erases an effect: it frees the effect id and mark as unused the memory * allocated for the parameters
*/ staticint iforce_erase_effect(struct input_dev *dev, int effect_id)
{ struct iforce *iforce = input_get_drvdata(dev); struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id]; int err = 0;
if (test_bit(FF_MOD1_IS_USED, core_effect->flags))
err = release_resource(&core_effect->mod1_chunk);
if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags))
err = release_resource(&core_effect->mod2_chunk);
/* TODO: remember to change that if more FF_MOD* bits are added */
core_effect->flags[0] = 0;
if (test_bit(EV_FF, dev->evbit)) { /* Check: no effects should be present in memory */ for (i = 0; i < dev->ff->max_effects; i++) { if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) {
dev_warn(&dev->dev, "%s: Device still owns effects\n",
__func__); break;
}
}
/* Disable force feedback playback */
iforce_send_packet(iforce, FF_CMD_ENABLE, "\001"); /* Wait for the command to complete */
wait_event_interruptible(iforce->wait,
!test_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags));
}
iforce->xport_ops->stop_io(iforce);
}
int iforce_init_device(struct device *parent, u16 bustype, struct iforce *iforce)
{ struct input_dev *input_dev; struct ff_device *ff;
u8 c[] = "CEOV";
u8 buf[IFORCE_MAX_LENGTH];
size_t len; int i, error; int ff_effects = 0;
input_dev = input_allocate_device(); if (!input_dev) return -ENOMEM;
/* * Wait until device ready - until it sends its first response.
*/
for (i = 0; i < 20; i++) if (!iforce_get_id_packet(iforce, 'O', buf, &len)) break;
if (i == 20) { /* 5 seconds */
dev_err(&input_dev->dev, "Timeout waiting for response from device.\n");
error = -ENODEV; goto fail;
}
/* * Get device info.
*/
if (!iforce_get_id_packet(iforce, 'M', buf, &len) && len >= 3)
input_dev->id.vendor = get_unaligned_le16(buf + 1); else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet M\n");
if (!iforce_get_id_packet(iforce, 'P', buf, &len) && len >= 3)
input_dev->id.product = get_unaligned_le16(buf + 1); else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet P\n");
if (!iforce_get_id_packet(iforce, 'B', buf, &len) && len >= 3)
iforce->device_memory.end = get_unaligned_le16(buf + 1); else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet B\n");
if (!iforce_get_id_packet(iforce, 'N', buf, &len) && len >= 2)
ff_effects = buf[1]; else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet N\n");
/* Check if the device can store more effects than the driver can really handle */ if (ff_effects > IFORCE_EFFECTS_MAX) {
dev_warn(&iforce->dev->dev, "Limiting number of effects to %d (device reports %d)\n",
IFORCE_EFFECTS_MAX, ff_effects);
ff_effects = IFORCE_EFFECTS_MAX;
}
/* * Display additional info.
*/
for (i = 0; c[i]; i++) if (!iforce_get_id_packet(iforce, c[i], buf, &len))
iforce_dump_packet(iforce, "info",
(FF_CMD_QUERY & 0xff00) | len, buf);
/* * Disable spring, enable force feedback.
*/
iforce_set_autocenter(input_dev, 0);
/* * Find appropriate device entry
*/
for (i = 0; iforce_device[i].idvendor; i++) if (iforce_device[i].idvendor == input_dev->id.vendor &&
iforce_device[i].idproduct == input_dev->id.product) break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.