Listing 4. squares.c

void ex3_timeout(unsigned long unused /*UNUSED*/)
{
    /* move in a small square */
    if (state<30) 
	input_report_rel(&ex3_dev, REL_X, 5);
    else if (state < 60)
	input_report_rel(&ex3_dev, REL_Y, 5);
    else if (state < 90)
	input_report_rel(&ex3_dev, REL_X, -5);
    else
	input_report_rel(&ex3_dev, REL_Y, -5);
    
    input_sync(&ex3_dev);
    
    if ((state++) >= 120)
	state = 0;
    
    /* set timer for 0.02 seconds */
    mod_timer(&ex3_dev.timer, jiffies+HZ/50);
}

static int __init ex3_init(void)
{
    /* extra safe initialization */
    memset(&ex3_dev, 0, sizeof(struct input_dev));
    init_input_dev(&ex3_dev);

    /* set up descriptive labels */
    ex3_dev.name = "Example 3 device";
    /* phys is unique on a running system */
    ex3_dev.phys = "A/Fake/Path";
    ex3_dev.id.bustype = BUS_HOST;
    ex3_dev.id.vendor = 0x0001;
    ex3_dev.id.product = 0x0003;
    ex3_dev.id.version = 0x0100;

    /* this device has two relative axes */
    set_bit(EV_REL, ex3_dev.evbit);
    set_bit(REL_X, ex3_dev.relbit);
    set_bit(REL_Y, ex3_dev.relbit);
    
    /* it needs a button to look like a mouse */
    set_bit(EV_KEY, ex3_dev.evbit);
    set_bit(BTN_LEFT, ex3_dev.keybit);
    
    /* and finally register with the input core */
    input_register_device(&ex3_dev);
    
    /* set up a repeating timer */
    init_timer(&ex3_dev.timer);
    ex3_dev.timer.function = ex3_timeout;
    ex3_dev.timer.expires = jiffies + HZ/10;
    add_timer(&ex3_dev.timer);
    
    return 0;
}

static void __exit ex3_exit(void)
{
    del_timer_sync(&ex3_dev.timer);
    input_unregister_device(&ex3_dev);
}

module_init(ex3_init);
module_exit(ex3_exit);