⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 leddev.c

📁 LINUX内核编程的一些程序例子
💻 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 + -