📄 lirc_dev.c
字号:
/* * LIRC base driver * * (L) by Artur Lipowski <alipowski@kki.net.pl> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: lirc_dev.c,v 1.18 2001/12/12 20:26:01 ranty Exp $ * */#ifdef HAVE_CONFIG_H# include <config.h>#endif #include <linux/version.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)#define LIRC_HAVE_DEVFS#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 4)#error "********************************************************"#error " Sorry, this driver needs kernel version 2.2.4 or higher"#error "********************************************************"#endif#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/ioctl.h>#include <linux/fs.h>#include <linux/poll.h>#ifdef LIRC_HAVE_DEVFS#include <linux/devfs_fs_kernel.h>#endif#include <linux/smp_lock.h>#include <asm/uaccess.h>#include <asm/semaphore.h>#include <asm/errno.h>#include <linux/wrapper.h>#define __KERNEL_SYSCALLS__#include <linux/unistd.h>#include "drivers/lirc.h"#include "lirc_dev.h"static int debug = 0;MODULE_PARM(debug,"i");#define IRCTL_DEV_NAME "BaseRemoteCtl"#define IRLOCK down_interruptible(&ir->lock)#define IRUNLOCK up(&ir->lock)#define SUCCESS 0#define NOPLUG -1#define dprintk if (debug) printk#define LOGHEAD "lirc_dev (%s[%d]): "struct irctl{ struct lirc_plugin p; int open; unsigned long features; unsigned int buf_len; int bytes_in_key; unsigned char buffer[BUFLEN]; unsigned int in_buf; int head, tail; int tpid; struct semaphore *t_notify; int shutdown; long jiffies_to_wait; wait_queue_head_t wait_poll; struct semaphore lock;#ifdef LIRC_HAVE_DEVFS devfs_handle_t devfs_handle;#endif};DECLARE_MUTEX(plugin_lock);static struct irctl irctls[MAX_IRCTL_DEVICES];static struct file_operations fops;/* helper function * initializes the irctl structure */static inline void init_irctl(struct irctl *ir){ memset(&ir->p, 0, sizeof(struct lirc_plugin)); ir->p.minor = NOPLUG; ir->buf_len = 0; ir->bytes_in_key = 0; ir->features = 0; ir->tpid = -1; ir->t_notify = NULL; ir->shutdown = 0; ir->jiffies_to_wait = 0; memset(&ir->buffer, 0, BUFLEN); ir->in_buf = 0; ir->head = ir->tail = 0; ir->open = 0;}/* helper function * reads key codes from plugin and puts them into buffer * buffer free space is checked and locking performed * returns 0 on success */inline static int add_to_buf(struct irctl *ir){ unsigned char buf[BUFLEN]; unsigned int i; if (ir->in_buf == ir->buf_len) { dprintk(LOGHEAD "buffer overflow\n", ir->p.name, ir->p.minor); return -EOVERFLOW; } for (i=0; i < ir->bytes_in_key; i++) { if (ir->p.get_key(ir->p.data, &buf[i], i)) { return -ENODATA; } dprintk(LOGHEAD "remote code (0x%x) now in buffer\n", ir->p.name, ir->p.minor, buf[i]); } /* here is the only point at which we add key codes to the buffer */ IRLOCK; memcpy(&ir->buffer[ir->tail], buf, ir->bytes_in_key); ir->tail += ir->bytes_in_key; ir->tail %= ir->buf_len; ir->in_buf += ir->bytes_in_key; IRUNLOCK; return SUCCESS;}/* main function of the polling thread */static int lirc_thread(void *irctl){ struct irctl *ir = irctl; lock_kernel(); /* This thread doesn't need any user-level access, * so get rid of all our resources */ exit_mm(current); exit_files(current); exit_fs(current); current->session = 1; current->pgrp = 1; current->euid = 0; current->tty = NULL; sigfillset(¤t->blocked); strcpy(current->comm, "lirc_dev"); unlock_kernel(); if (ir->t_notify != NULL) { up(ir->t_notify); } dprintk(LOGHEAD "poll thread started\n", ir->p.name, ir->p.minor); do { if (ir->open) { if (ir->jiffies_to_wait) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(ir->jiffies_to_wait); } else { interruptible_sleep_on(ir->p.get_queue(ir->p.data)); } if (signal_pending(current)) { break; } if (!add_to_buf(ir)) { wake_up_interruptible(&ir->wait_poll); } } else { /* if device not opened so we can sleep half a second */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ/2); } } while (!ir->shutdown && !signal_pending(current)); ir->tpid = -1; if (ir->t_notify != NULL) { up(ir->t_notify); } dprintk(LOGHEAD "poll thread ended\n", ir->p.name, ir->p.minor); return 0;}/* * */int lirc_register_plugin(struct lirc_plugin *p){ struct irctl *ir; int minor;#ifdef LIRC_HAVE_DEVFS char name[16];#endif DECLARE_MUTEX_LOCKED(tn); if (!p) { printk("lirc_dev: lirc_register_plugin:" "plugin pointer must be not NULL!\n"); return -EBADRQC; } if (MAX_IRCTL_DEVICES <= p->minor) { printk("lirc_dev: lirc_register_plugin:" "\" minor\" must be beetween 0 and %d (%d)!\n", MAX_IRCTL_DEVICES-1, p->minor); return -EBADRQC; } if (1 > p->code_length || (BUFLEN*8) < p->code_length) { printk("lirc_dev: lirc_register_plugin:" "code length in bits for minor (%d) " "must be less than %d!\n", p->minor, BUFLEN*8); return -EBADRQC; } if (p->sample_rate) { if (2 > p->sample_rate || 50 < p->sample_rate) { printk("lirc_dev: lirc_register_plugin:" "sample_rate must be beetween 2 and 50!\n"); return -EBADRQC; } } else { if (!p->get_queue) { printk("lirc_dev: lirc_register_plugin:" "get_queue cannot be NULL!\n"); return -EBADRQC; } } down_interruptible(&plugin_lock); minor = p->minor; if (0 > minor) { /* find first free slot for plugin */ for (minor=0; minor<MAX_IRCTL_DEVICES; minor++) if (irctls[minor].p.minor == NOPLUG) break; if (MAX_IRCTL_DEVICES == minor) { printk("lirc_dev: lirc_register_plugin: " "no free slots for plugins!\n"); up(&plugin_lock); return -ENOMEM; } } else if (irctls[minor].p.minor != NOPLUG) { printk("lirc_dev: lirc_register_plugin:" "minor (%d) just registerd!\n", minor); up(&plugin_lock); return -EBUSY; } ir = &irctls[minor]; if (p->sample_rate) { ir->jiffies_to_wait = HZ / p->sample_rate; } else { /* it means - wait for externeal event in task queue */ ir->jiffies_to_wait = 0; } /* some safety check 8-) */ p->name[sizeof(p->name)-1] = '\0'; ir->bytes_in_key = p->code_length/8 + (p->code_length%8 ? 1 : 0); /* this simplifies boundary checking during buffer access */ ir->buf_len = BUFLEN - (BUFLEN%ir->bytes_in_key); ir->features = (p->code_length > 8) ? LIRC_CAN_REC_LIRCCODE : LIRC_CAN_REC_CODE; ir->p = *p; ir->p.minor = minor;#ifdef LIRC_HAVE_DEVFS sprintf (name, DEV_LIRC "/%d", ir->p.minor); ir->devfs_handle = devfs_register(NULL, name, DEVFS_FL_DEFAULT, IRCTL_DEV_MAJOR, ir->p.minor, S_IFCHR | S_IRUSR | S_IWUSR, &fops, NULL);#endif /* try to fire up polling thread */ ir->t_notify = &tn; ir->tpid = kernel_thread(lirc_thread, (void*)ir, 0); if (ir->tpid < 0) { IRUNLOCK; up(&plugin_lock); printk("lirc_dev: lirc_register_plugin:" "cannot run poll thread for minor = %d\n", p->minor); return -ECHILD; } down(&tn); ir->t_notify = NULL; up(&plugin_lock); MOD_INC_USE_COUNT; dprintk("lirc_dev: plugin %s registered at minor number = %d\n", ir->p.name, ir->p.minor); return minor;}/* * */int lirc_unregister_plugin(int minor){ struct irctl *ir;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -