/* * Debug driver that continuosly blink LEDs on keyboards * * Copyright (c) 2007 Dmitry Torokhov */ /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. */ #include #include #include #include #include MODULE_AUTHOR("Dmitry Torokhov "); MODULE_DESCRIPTION("Blink driver"); MODULE_LICENSE("GPL"); struct blinker { struct delayed_work work; struct input_handle handle; int state; }; static void blink_task_handler(struct work_struct *work) { struct blinker *blinker = container_of(work, struct blinker, work.work); blinker->state = !blinker->state; input_inject_event(&blinker->handle, EV_LED, LED_NUML, blinker->state); schedule_delayed_work(&blinker->work, msecs_to_jiffies(250)); } static void blink_event(struct input_handle *handle, unsigned int type, unsigned int code, int down) { /* * This is a very rare handler that does not process any input * events; just injects them. */ } static int blink_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { struct blinker *blinker; struct input_handle *handle; int error; blinker = kzalloc(sizeof(struct blinker), GFP_KERNEL); if (!blinker) return -ENOMEM; INIT_DELAYED_WORK(&blinker->work, blink_task_handler); handle = &blinker->handle; handle->dev = dev; handle->handler = handler; handle->name = "blink"; handle->private = blinker; error = input_register_handle(handle); if (error) goto err_free_handle; error = input_open_device(handle); if (error) goto err_unregister_handle; schedule_delayed_work(&blinker->work, 0); return 0; err_unregister_handle: input_unregister_handle(handle); err_free_handle: kfree(handle); return error; } static void blink_disconnect(struct input_handle *handle) { struct blinker *blinker = handle->private; cancel_rearming_delayed_work(&blinker->work); input_close_device(handle); input_unregister_handle(handle); kfree(blinker); } static const struct input_device_id blink_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_LEDBIT, .evbit = { BIT(EV_LED) }, .keybit = { [LONG(LED_NUML)] = BIT(LED_NUML) }, }, { } }; static struct input_handler blink_handler = { .event = blink_event; .connect = blink_connect, .disconnect = blink_disconnect, .name = "blink", .id_table = blink_ids, }; static int __init blink_handler_init(void) { return input_register_handler(&blink_handler); } static void __exit blink_handler_exit(void) { input_unregister_handler(&blink_handler); flush_scheduled_work(); } module_init(blink_handler_init); module_exit(blink_handler_exit);