📄 leddev.c
字号:
/* leddev.c * * led input handler * */#include <asm/io.h>#include <asm/system.h>#include <asm/segment.h>#include <asm/types.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/time.h>#include <linux/input.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/miscdevice.h>#include <linux/module.h>#include <linux/poll.h> /* poll_wait */#include <linux/init.h>#include <linux/smp_lock.h> MODULE_AUTHOR("marco corvi <marco_corvi@geocities.com>");MODULE_DESCRIPTION("LED device driver");/* MODULE_LICENSE("GPL"); */MODULE_SUPPORTED_DEVICE("input/led");#include "leddev.h"/* minors are so assigned: see the drivers/input directory * joydev 0 - 31 * mousedev 32 - 63 * event 64 - 95 */#define LEDDEV_MINOR_BASE 96#define LEDDEV_MINORS 4// this must be a power of 2#define LEDDEV_BUFFER_SIZE 64#if 0struct led_event { __u32 time; /* event timestamp in milliseconds */ __s16 value; /* value */ __u8 type; /* event type */ __u8 number; /* number */}; #endifstruct led_handle { int open; int in_use; int minor; struct input_handle handle; /* input handle */ wait_queue_head_t wait; devfs_handle_t devfs; struct input_event event[LEDDEV_BUFFER_SIZE]; /* event buffer */ int event_head; int event_tail; struct fasync_struct * fasync;};/* Array of LEDEV_MINORS led_handle struct's */static struct led_handle leddev[ LEDDEV_MINORS ];/* ------------------------------------------------------------------- * event function * * From input.h: * #define LED_NUML 0x00 * #define LED_CAPSL 0x01 * #define LED_SCROLLL 0x02 * #define LED_COMPOSE 0x03 * #define LED_KANA 0x04 * #define LED_SLEEP 0x05 * #define LED_SUSPEND 0x06 * #define LED_MUTE 0x07 * #define LED_MISC 0x08 * #define LED_MAX 0x0f * ------------------------------------------------------------------- */static void leddev_event( struct input_handle * handle, unsigned int type, unsigned int code, int value){ struct led_handle * led_h = (struct led_handle *)(handle->private); struct input_event * event = &( led_h->event[ led_h->event_head ] ); switch (type) { case EV_LED: if ( code > LED_MAX ) return; if ( value < 0 || value > 0x07 ) return; event->type = EV_LED; event->code = code; event->value = value; break; default: return; } get_fast_time ( & event->time ); // printk( KERN_ALERT "Leddev Event %d %d \n", code, value ); led_h->event_head = ( led_h->event_head + 1 ) % LEDDEV_BUFFER_SIZE; /* when the head reaches the tail, stale events are overwritten */ if ( led_h->event_head == led_h->event_tail ) led_h->event_tail = ( led_h->event_tail + 1 ) % LEDDEV_BUFFER_SIZE; kill_fasync( &(led_h->fasync), SIGIO, POLL_IN ); wake_up_interruptible( &(led_h->wait) );}/* ------------------------------------------------------------------- * File Operation functions * ------------------------------------------------------------------- */static int leddev_fasync( int fd, struct file *file, int on ){ int retval; struct led_handle * led_h = file->private_data; retval = fasync_helper( fd, file, on, &(led_h->fasync) ); return retval < 0 ? retval : 0;}static int leddev_release(struct inode * inode, struct file * file){ struct led_handle * led_h = file->private_data; lock_kernel(); leddev_fasync(-1, file, 0); -- led_h->open; if ( led_h->open == 0 ) if ( led_h->in_use ) input_close_device( & led_h->handle ); unlock_kernel(); return 0;}static int leddev_open(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev) - LEDDEV_MINOR_BASE; struct led_handle * led_h; if (minor >= LEDDEV_MINORS ) return -ENODEV; // printk(KERN_ALERT "leddev_open minor %d\n", minor); led_h = & (leddev[minor]); file->private_data = led_h; /* if the handle was not open, handle.open ++ * and, if handle.dev->open exists, invoke it */ if ( led_h->open == 0 ) if ( led_h->in_use ) input_open_device(& led_h->handle ); led_h->open ++; return 0;}static ssize_t leddev_write( struct file * file, const char * buffer, size_t count, loff_t *ppos){ return -EINVAL;}static ssize_t leddev_read( struct file *file, char *buf, size_t count, loff_t *ppos){ DECLARE_WAITQUEUE(wait, current); struct led_handle * led_h = file->private_data; // struct input_dev * input = led_h->handle.dev; struct input_event * event; int retval = 0; int cnt; int max_count; // printk(KERN_ALERT "leddev_read count %d\n", count ); if (count < sizeof(struct input_event)) return -EINVAL; if ( led_h->event_head == led_h->event_tail ) { // printk(KERN_ALERT "leddev_read waits\n"); add_wait_queue( & led_h->wait, &wait); current->state = TASK_INTERRUPTIBLE; while (led_h->event_head == led_h->event_tail) { if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; break; } if (signal_pending(current)) { retval = -ERESTARTSYS; break; } schedule(); } current->state = TASK_RUNNING; remove_wait_queue( & led_h->wait, &wait); } if (retval) return retval; if ( led_h->event_tail > led_h->event_head ) { max_count = led_h->event_head + ( LEDDEV_BUFFER_SIZE - led_h->event_tail ); } else { max_count = led_h->event_head - led_h->event_tail; } count /= sizeof( struct input_event ); if ( count > max_count ) count = max_count; cnt = 0; while (cnt < count) { event = & led_h->event[ (led_h->event_tail + cnt) % LEDDEV_BUFFER_SIZE ]; if (copy_to_user(buf, event, sizeof(struct input_event))) return -EFAULT; cnt ++; } led_h->event_tail = (led_h->event_tail + cnt) % LEDDEV_BUFFER_SIZE ; // printk(KERN_ALERT "leddev_read cnt %d head %d tail %d\n", // cnt, led_h->event_head, led_h->event_tail ); return cnt * sizeof( struct input_event );}static unsigned int leddev_poll( struct file *file, poll_table *wait ){ struct led_handle * led_h = file->private_data; /* poll_wait( file, &led_h->wait, wait); */ if ( wait && &(led_h->wait) ) __pollwait( file, &led_h->wait, wait ); if ( led_h->event_head != led_h->event_tail ) return POLLIN | POLLRDNORM; return 0;}static int leddev_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ // struct led_handle * led_h = file->private_data; if ( cmd == LEDDEV_IOC_HARDRESET ) { while ( MOD_IN_USE ) MOD_DEC_USE_COUNT; MOD_INC_USE_COUNT; return 0; } return -EINVAL;}static struct file_operations leddev_fops = { owner: THIS_MODULE, read: leddev_read, write: leddev_write, poll: leddev_poll, open: leddev_open, release: leddev_release, ioctl: leddev_ioctl, fasync: leddev_fasync,};/* ------------------------------------------------------------------- * Input Core functions * ------------------------------------------------------------------- */static struct input_handle *leddev_connect( struct input_handler *handler, struct input_dev *dev){ struct led_handle * led_h; int minor = 0; // printk(KERN_ALERT "leddev_connect %s\n", dev->name); // could also test dev->ledbit if ( ! test_bit(EV_LED, dev->evbit) ) return NULL; for ( minor=0; minor<LEDDEV_MINORS; minor++) if ( leddev[minor].in_use == 0 ) break; if ( minor == LEDDEV_MINORS ) return NULL; led_h = &( leddev[minor] ); // printk(KERN_ALERT "leddev_connect minor %d handle %p handler %p\n", // minor, &(led_h->handle), handler ); /* The other fields of handle are set by the input core */ led_h->handle.dev = dev; led_h->handle.handler = handler; led_h->handle.private = led_h; led_h->in_use = 1; if ( led_h->open ) input_open_device(& led_h->handle ); return & led_h->handle;}static void leddev_disconnect(struct input_handle *handle){ struct led_handle * led_h = handle->private; if ( led_h->open ) if ( led_h->in_use ) /* unnecessary: should be in use for sure */ input_close_device( handle ); led_h->in_use = 0;} static struct input_handler leddev_handler = { event: leddev_event, connect: leddev_connect, disconnect: leddev_disconnect, fops: &leddev_fops, minor: LEDDEV_MINOR_BASE,};/* ------------------------------------------------------------------ * Module init and exit * ------------------------------------------------------------------ */static int __init leddev_init(void){ int minor; struct led_handle * led_h; /* leddev = kmalloc( LEDDEV_MINORS * sizeof(struct led_handle), GFP_KERNEL ); if ( leddev == NULL ) return 1; memset( leddev, 0, LEDDEV_MINORS * sizeof( struct led_handle ) ); */ for ( minor = 0; minor < LEDDEV_MINORS; minor++ ) { led_h = &( leddev[minor] ); memset( led_h, 0, sizeof( struct led_handle ) ); /* * led_h->open = 0; * led_h->in_use = 0; * led_h->handle; * led_h->event[LEDDEV_BUFFER_SIZE]; * led_h->event_head = 0; * led_h->event_tail = 0; * led_h->fasync = 0; */ init_waitqueue_head(&led_h->wait); led_h->minor = minor; led_h->devfs = input_register_minor("led%d", minor, LEDDEV_MINOR_BASE); } input_register_handler(&leddev_handler); // printk(KERN_ALERT "leddev_handler %p\n", &leddev_handler ); return 0;}static void __exit leddev_exit(void){ int minor; struct led_handle * led_h; input_unregister_handler(&leddev_handler); for ( minor = 0; minor < LEDDEV_MINORS; minor++ ) { led_h = &( leddev[minor] ); input_unregister_minor( led_h->devfs ); } /* kfree( leddev ); */}module_init(leddev_init);module_exit(leddev_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -