📄 iforce.c
字号:
*/static int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect){ u8 wave_code; int core_id = effect->id; struct iforce_core_effect* core_effect = iforce->core_effects + core_id; struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); int err = 0; err = make_period_modifier(iforce, mod1_chunk, effect->u.periodic.magnitude, effect->u.periodic.offset, effect->u.periodic.period, effect->u.periodic.phase); if (err) return err; set_bit(FF_MOD1_IS_USED, core_effect->flags); err = make_shape_modifier(iforce, mod2_chunk, effect->u.periodic.shape.attack_length, effect->u.periodic.shape.attack_level, effect->u.periodic.shape.fade_length, effect->u.periodic.shape.fade_level); if (err) return err; set_bit(FF_MOD2_IS_USED, core_effect->flags); switch (effect->u.periodic.waveform) { case FF_SQUARE: wave_code = 0x20; break; case FF_TRIANGLE: wave_code = 0x21; break; case FF_SINE: wave_code = 0x22; break; case FF_SAW_UP: wave_code = 0x23; break; case FF_SAW_DOWN: wave_code = 0x24; break; default: wave_code = 0x20; break; } err = make_core(iforce, effect->id, mod1_chunk->start, mod2_chunk->start, wave_code, 0x20, effect->replay.length, effect->replay.delay, effect->trigger.button, effect->trigger.interval, effect->u.periodic.direction); return err;}/* * Upload a constant force effect */static int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect){ int core_id = effect->id; struct iforce_core_effect* core_effect = iforce->core_effects + core_id; struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); int err = 0; printk(KERN_DEBUG "iforce.c: make constant effect\n"); err = make_magnitude_modifier(iforce, mod1_chunk, effect->u.constant.level); if (err) return err; set_bit(FF_MOD1_IS_USED, core_effect->flags); err = make_shape_modifier(iforce, mod2_chunk, effect->u.constant.shape.attack_length, effect->u.constant.shape.attack_level, effect->u.constant.shape.fade_length, effect->u.constant.shape.fade_level); if (err) return err; set_bit(FF_MOD2_IS_USED, core_effect->flags); err = make_core(iforce, effect->id, mod1_chunk->start, mod2_chunk->start, 0x00, 0x20, effect->replay.length, effect->replay.delay, effect->trigger.button, effect->trigger.interval, effect->u.constant.direction); return err;}/* * Upload an interactive effect. Those are for example friction, inertia, springs... */static int iforce_upload_interactive(struct iforce* iforce, struct ff_effect* effect){ int core_id = effect->id; struct iforce_core_effect* core_effect = iforce->core_effects + core_id; struct resource* mod_chunk = &(core_effect->mod1_chunk); u8 type, axes; u16 mod1, mod2, direction; int err = 0; printk(KERN_DEBUG "iforce.c: make interactive effect\n"); switch (effect->type) { case FF_SPRING: type = 0x40; break; case FF_FRICTION: type = 0x41; break; default: return -1; } err = make_interactive_modifier(iforce, mod_chunk, effect->u.interactive.right_saturation, effect->u.interactive.left_saturation, effect->u.interactive.right_coeff, effect->u.interactive.left_coeff, effect->u.interactive.deadband, effect->u.interactive.center); if (err) return err; set_bit(FF_MOD1_IS_USED, core_effect->flags); switch ((test_bit(ABS_X, &effect->u.interactive.axis) || test_bit(ABS_WHEEL, &effect->u.interactive.axis)) | (!!test_bit(ABS_Y, &effect->u.interactive.axis) << 1)) { case 0: /* Only one axis, choose orientation */ mod1 = mod_chunk->start; mod2 = 0xffff; direction = effect->u.interactive.direction; axes = 0x20; break; case 1: /* Only X axis */ mod1 = mod_chunk->start; mod2 = 0xffff; direction = 0x5a00; axes = 0x40; break; case 2: /* Only Y axis */ mod1 = 0xffff; mod2 = mod_chunk->start; direction = 0xb400; axes = 0x80; break; case 3: /* Both X and Y axes */ /* TODO: same setting for both axes is not mandatory */ mod1 = mod_chunk->start; mod2 = mod_chunk->start; direction = 0x6000; axes = 0xc0; break; default: return -1; } err = make_core(iforce, effect->id, mod1, mod2, type, axes, effect->replay.length, effect->replay.delay, effect->trigger.button, effect->trigger.interval, direction); return err;}/* * Function called when an ioctl is performed on the event dev entry. * It uploads an effect to the device */static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect){ struct iforce* iforce = (struct iforce*)(dev->private); int id; printk(KERN_DEBUG "iforce.c: upload effect\n");/* * Get a free id */ for (id=0; id < FF_EFFECTS_MAX; ++id) if (!test_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break; if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max) return -ENOMEM; effect->id = id; set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags);/* * Upload the effect */ switch (effect->type) { case FF_PERIODIC: return iforce_upload_periodic(iforce, effect); case FF_CONSTANT: return iforce_upload_constant(iforce, effect); case FF_SPRING: case FF_FRICTION: return iforce_upload_interactive(iforce, effect); default: return -1; }}/* * Erases an effect: it frees the effect id and mark as unused the memory * allocated for the parameters */static int iforce_erase_effect(struct input_dev *dev, int effect_id){ struct iforce* iforce = (struct iforce*)(dev->private); int err = 0; struct iforce_core_effect* core_effect; printk(KERN_DEBUG "iforce.c: erase effect %d\n", effect_id); if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX) return -EINVAL; core_effect = iforce->core_effects + effect_id; if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk)); if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk)); /*TODO: remember to change that if more FF_MOD* bits are added */ core_effect->flags[0] = 0; return err;}static int iforce_init_device(struct iforce *iforce){ unsigned char c[] = "CEOV"; int i; init_waitqueue_head(&iforce->wait); iforce->dev.ff_effects_max = 10;/* * Input device fields. */ iforce->dev.idbus = BUS_USB; iforce->dev.private = iforce; iforce->dev.name = iforce->name; iforce->dev.open = iforce_open; iforce->dev.close = iforce_close; iforce->dev.event = iforce_input_event; iforce->dev.upload_effect = iforce_upload_effect; iforce->dev.erase_effect = iforce_erase_effect;/* * On-device memory allocation. */ iforce->device_memory.name = "I-Force device effect memory"; iforce->device_memory.start = 0; iforce->device_memory.end = 200; iforce->device_memory.flags = IORESOURCE_MEM; iforce->device_memory.parent = NULL; iforce->device_memory.child = NULL; iforce->device_memory.sibling = NULL;/* * Wait until device ready - until it sends its first response. */ for (i = 0; i < 20; i++) if (!get_id_packet(iforce, "O")) break; if (i == 20) { /* 5 seconds */ printk(KERN_ERR "iforce.c: Timeout waiting for response from device.\n"); iforce_close(&iforce->dev); return -1; }/* * Get device info. */ if (!get_id_packet(iforce, "M")) iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1]; if (!get_id_packet(iforce, "P")) iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1]; if (!get_id_packet(iforce, "B")) iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1]; if (!get_id_packet(iforce, "N")) iforce->dev.ff_effects_max = iforce->edata[1];/* * Display additional info. */ for (i = 0; c[i]; i++) if (!get_id_packet(iforce, c + i)) dump_packet("info", iforce->ecmd, iforce->edata);/* * Disable spring, enable force feedback. * FIXME: We should use iforce_set_autocenter() et al here. */ send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000"); send_packet(iforce, FF_CMD_ENABLE, "\004");/* * Find appropriate device entry */ for (i = 0; iforce_device[i].idvendor; i++) if (iforce_device[i].idvendor == iforce->dev.idvendor && iforce_device[i].idproduct == iforce->dev.idproduct) break; iforce->type = iforce_device + i; sprintf(iforce->name, iforce->type->name, iforce->dev.idproduct, iforce->dev.idvendor);/* * Set input device bitfields and ranges. */ iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF); for (i = 0; iforce->type->btn[i] >= 0; i++) { signed short t = iforce->type->btn[i]; set_bit(t, iforce->dev.keybit); if (t != BTN_DEAD) set_bit(FF_BTN(t), iforce->dev.ffbit); } for (i = 0; iforce->type->abs[i] >= 0; i++) { signed short t = iforce->type->abs[i]; set_bit(t, iforce->dev.absbit); switch (t) { case ABS_X: case ABS_Y: case ABS_WHEEL: iforce->dev.absmax[t] = 1920; iforce->dev.absmin[t] = -1920; iforce->dev.absflat[t] = 128; iforce->dev.absfuzz[t] = 16; set_bit(FF_ABS(t), iforce->dev.ffbit); break; case ABS_THROTTLE: case ABS_GAS: case ABS_BRAKE: iforce->dev.absmax[t] = 255; iforce->dev.absmin[t] = 0; break; case ABS_HAT0X: case ABS_HAT0Y: iforce->dev.absmax[t] = 1; iforce->dev.absmin[t] = -1; break; } } for (i = 0; iforce->type->ff[i] >= 0; i++) set_bit(iforce->type->ff[i], iforce->dev.ffbit);/* * Register input device. */ input_register_device(&iforce->dev); return 0;}#ifdef IFORCE_USBstatic void iforce_usb_irq(struct urb *urb){ struct iforce *iforce = urb->context; if (urb->status) return; iforce_process_packet(iforce, (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1);}static void iforce_usb_out(struct urb *urb){ struct iforce *iforce = urb->context; if (urb->status) return; if (waitqueue_active(&iforce->wait)) wake_up(&iforce->wait);}static void iforce_usb_ctrl(struct urb *urb){ struct iforce *iforce = urb->context; if (urb->status) return; iforce->ecmd = 0xff00 | urb->actual_length; if (waitqueue_active(&iforce->wait)) wake_up(&iforce->wait);}static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id){ struct usb_endpoint_descriptor *epirq, *epout; struct iforce *iforce; epirq = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; epout = dev->config[0].interface[ifnum].altsetting[0].endpoint + 1; if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL; memset(iforce, 0, sizeof(struct iforce)); iforce->bus = IFORCE_USB; iforce->usbdev = dev; iforce->dr.requesttype = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; iforce->dr.index = 0; iforce->dr.length = 16; FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); FILL_BULK_URB(&iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress), iforce + 1, 32, iforce_usb_out, iforce); FILL_CONTROL_URB(&iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), (void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce); if (iforce_init_device(iforce)) { kfree(iforce); return NULL; } printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on usb%d:%d.%d\n", iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max, iforce->device_memory.end, dev->bus->busnum, dev->devnum, ifnum); return iforce;}static void iforce_usb_disconnect(struct usb_device *dev, void *ptr){ struct iforce *iforce = ptr; usb_unlink_urb(&iforce->irq); input_unregister_device(&iforce->dev); kfree(iforce);}static struct usb_device_id iforce_usb_ids [] = { { USB_DEVICE(0x046d, 0xc281) }, /* Logitech WingMan Force */ { USB_DEVICE(0x046d, 0xc291) }, /* Logitech WingMan Formula Force */ { USB_DEVICE(0x05ef, 0x020a) }, /* AVB Top Shot Pegasus */ { USB_DEVICE(0x05ef, 0x8884) }, /* AVB Mag Turbo Force */ { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */ { } /* Terminating entry */};MODULE_DEVICE_TABLE (usb, iforce_usb_ids);static struct usb_driver iforce_usb_driver = { name: "iforce", probe: iforce_usb_probe, disconnect: iforce_usb_disconnect, id_table: iforce_usb_ids,};#endif#ifdef IFORCE_232static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags){ struct iforce* iforce = serio->private; if (!iforce->pkt) { if (data != 0x2b) { return; } iforce->pkt = 1; return; } if (!iforce->id) { if (data > 3 && data != 0xff) { iforce->pkt = 0; return; } iforce->id = data; return; } if (!iforce->len) { if (data > IFORCE_MAX_LENGTH) { iforce->pkt = 0; iforce->id = 0; return; } iforce->len = data; return; } if (iforce->idx < iforce->len) { iforce->csum += iforce->data[iforce->idx++] = data; return; } if (iforce->idx == iforce->len) { iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data); iforce->pkt = 0; iforce->id = 0; iforce->len = 0; iforce->idx = 0; iforce->csum = 0; }}static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev){ struct iforce *iforce; if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) return; if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return; memset(iforce, 0, sizeof(struct iforce)); iforce->bus = IFORCE_232; iforce->serio = serio; serio->private = iforce; if (serio_open(serio, dev)) { kfree(iforce); return; } if (iforce_init_device(iforce)) { serio_close(serio); kfree(iforce); return; } printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on serio%d\n", iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max, iforce->device_memory.end, serio->number);}static void iforce_serio_disconnect(struct serio *serio){ struct iforce* iforce = serio->private; input_unregister_device(&iforce->dev); serio_close(serio); kfree(iforce);}static struct serio_dev iforce_serio_dev = { interrupt: iforce_serio_irq, connect: iforce_serio_connect, disconnect: iforce_serio_disconnect,};#endifstatic int __init iforce_init(void){#ifdef IFORCE_USB usb_register(&iforce_usb_driver);#endif#ifdef IFORCE_232 serio_register_device(&iforce_serio_dev);#endif return 0;}static void __exit iforce_exit(void){#ifdef IFORCE_USB usb_deregister(&iforce_usb_driver);#endif#ifdef IFORCE_232 serio_unregister_device(&iforce_serio_dev);#endif}module_init(iforce_init);module_exit(iforce_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -