📄 lirc_dev.c
字号:
DECLARE_MUTEX_LOCKED(tn); if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { printk("lirc_dev: lirc_unregister_plugin:" "\" minor\" must be beetween 0 and %d!\n", MAX_IRCTL_DEVICES-1); return -EBADRQC; } ir = &irctls[minor]; down_interruptible(&plugin_lock); if (ir->p.minor != minor) { printk("lirc_dev: lirc_unregister_plugin:" "minor (%d) device not registered!", minor); up(&plugin_lock); return -ENOENT; } if (ir->open) { printk("lirc_dev: lirc_unregister_plugin:" "plugin %s[%d] in use!", ir->p.name, ir->p.minor); up(&plugin_lock); return -EBUSY; } /* end up polling thread */ if (ir->tpid >= 0) { ir->t_notify = &tn; ir->shutdown = 1; down(&tn); ir->t_notify = NULL; } dprintk("lirc_dev: plugin %s unregistered from minor number = %d\n", ir->p.name, ir->p.minor);#ifdef LIRC_HAVE_DEVFS devfs_unregister(ir->devfs_handle);#endif init_irctl(ir); up(&plugin_lock); MOD_DEC_USE_COUNT; return SUCCESS;}/* * */static int irctl_open(struct inode *inode, struct file *file){ struct irctl *ir; if (MINOR(inode->i_rdev) >= MAX_IRCTL_DEVICES) { dprintk("lirc_dev [%d]: open result = -ENODEV\n", MINOR(inode->i_rdev)); return -ENODEV; } ir = &irctls[MINOR(inode->i_rdev)]; dprintk(LOGHEAD "open called\n", ir->p.name, ir->p.minor); down_interruptible(&plugin_lock); if (ir->p.minor == NOPLUG) { up(&plugin_lock); dprintk(LOGHEAD "open result = -ENODEV\n", ir->p.name, ir->p.minor); return -ENODEV; } if (ir->open) { up(&plugin_lock); dprintk(LOGHEAD "open result = -EBUSY\n", ir->p.name, ir->p.minor); return -EBUSY; } /* rhere is no need for locking here because ir->open is 0 * and lirc_thread isn't using buffer */ ir->head = ir->tail; ir->in_buf = 0; ++ir->open; ir->p.set_use_inc(ir->p.data); up(&plugin_lock); dprintk(LOGHEAD "open result = %d\n", ir->p.name, ir->p.minor, SUCCESS); return SUCCESS;}/* * */static int irctl_close(struct inode *inode, struct file *file){ struct irctl *ir = &irctls[MINOR(inode->i_rdev)]; dprintk(LOGHEAD "close called\n", ir->p.name, ir->p.minor); down_interruptible(&plugin_lock); --ir->open; ir->p.set_use_dec(ir->p.data); up(&plugin_lock); return SUCCESS;}/* * */static unsigned int irctl_poll(struct file *file, poll_table *wait){ struct irctl *ir = &irctls[MINOR(file->f_dentry->d_inode->i_rdev)]; dprintk(LOGHEAD "poll called\n", ir->p.name, ir->p.minor); if (!ir->in_buf) { poll_wait(file, &ir->wait_poll, wait); } dprintk(LOGHEAD "poll result = %s\n", ir->p.name, ir->p.minor, ir->in_buf ? "POLLIN|POLLRDNORM" : "SUCCESS"); return ir->in_buf ? (POLLIN|POLLRDNORM) : SUCCESS;}/* * */static int irctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ unsigned long mode; int result = SUCCESS; struct irctl *ir = &irctls[MINOR(inode->i_rdev)]; dprintk(LOGHEAD "poll called (%u)\n", ir->p.name, ir->p.minor, cmd); if (ir->p.minor == NOPLUG) { dprintk(LOGHEAD "ioctl result = -ENODEV\n", ir->p.name, ir->p.minor); return -ENODEV; } switch(cmd) { case LIRC_GET_FEATURES: result = put_user(ir->features, (unsigned long*)arg); break; case LIRC_GET_REC_MODE: result = put_user(LIRC_REC2MODE(ir->features), (unsigned long*)arg); break; case LIRC_SET_REC_MODE: result = get_user(mode, (unsigned long*)arg); if(!result && !(LIRC_MODE2REC(mode) & ir->features)) { result = -EINVAL; } break; case LIRC_GET_LENGTH: result = put_user((unsigned long)ir->p.code_length, (unsigned long *)arg); break; default: result = -ENOIOCTLCMD; } dprintk(LOGHEAD "ioctl result = %d\n", ir->p.name, ir->p.minor, result); return result;}/* * */static ssize_t irctl_read(struct file *file, char *buffer, size_t length, loff_t *ppos) { unsigned char buf[BUFLEN]; struct irctl *ir = &irctls[MINOR(file->f_dentry->d_inode->i_rdev)]; int ret; DECLARE_WAITQUEUE(wait, current); dprintk(LOGHEAD "read called\n", ir->p.name, ir->p.minor); if (ir->bytes_in_key != length) { dprintk(LOGHEAD "read result = -EIO\n", ir->p.name, ir->p.minor); return -EIO; } /* we add ourselves to the task queue before buffer check * to avoid losing scan code (in case when queue is awaken somewhere * beetwen while condition checking and scheduling) */ add_wait_queue(&ir->wait_poll, &wait); current->state = TASK_INTERRUPTIBLE; /* while input buffer is empty and device opened in blocking mode, * wait for input */ while (!ir->in_buf) { if (file->f_flags & O_NONBLOCK) { dprintk(LOGHEAD "read result = -EWOULDBLOCK\n", ir->p.name, ir->p.minor); remove_wait_queue(&ir->wait_poll, &wait); current->state = TASK_RUNNING; return -EWOULDBLOCK; } if (signal_pending(current)) { dprintk(LOGHEAD "read result = -ERESTARTSYS\n", ir->p.name, ir->p.minor); remove_wait_queue(&ir->wait_poll, &wait); current->state = TASK_RUNNING; return -ERESTARTSYS; } schedule(); current->state = TASK_INTERRUPTIBLE; } remove_wait_queue(&ir->wait_poll, &wait); current->state = TASK_RUNNING; /* here is the only point at which we remove key codes from * the buffer */ IRLOCK; memcpy(buf, &ir->buffer[ir->head], length); ir->head += length; ir->head %= ir->buf_len; ir->in_buf -= length; IRUNLOCK; ret = copy_to_user(buffer, buf, length); dprintk(LOGHEAD "read result = %s (%d)\n", ir->p.name, ir->p.minor, ret ? "-EFAULT" : "OK", ret); return ret ? -EFAULT : length;}static struct file_operations fops = { read: irctl_read, poll: irctl_poll, ioctl: irctl_ioctl, open: irctl_open, release: irctl_close};EXPORT_SYMBOL(lirc_register_plugin);EXPORT_SYMBOL(lirc_unregister_plugin);/* * */int lirc_dev_init(void){ int i; for (i=0; i < MAX_IRCTL_DEVICES; ++i) { init_irctl(&irctls[i]); init_MUTEX(&irctls[i].lock); init_waitqueue_head(&irctls[i].wait_poll); }#ifndef LIRC_HAVE_DEVFS i = register_chrdev(IRCTL_DEV_MAJOR,#else i = devfs_register_chrdev(IRCTL_DEV_MAJOR,#endif IRCTL_DEV_NAME, &fops); if (i < 0) { printk ("lirc_dev: device registration failed with %d\n", i); return i; } printk("lirc_dev: IR Remote Control driver registered, at major %d \n", IRCTL_DEV_MAJOR); return SUCCESS;}/* ---------------------------------------------------------------------- *//* For now dont try to use it as a static version ! */#ifdef MODULEMODULE_DESCRIPTION("LIRC base driver module");MODULE_AUTHOR("Artur Lipowski");#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endif/* * */int init_module(void){ return lirc_dev_init();}/* * */void cleanup_module(void){ int ret; #ifndef LIRC_HAVE_DEVFS ret = unregister_chrdev(IRCTL_DEV_MAJOR, IRCTL_DEV_NAME);#else ret = devfs_unregister_chrdev(IRCTL_DEV_MAJOR, IRCTL_DEV_NAME);#endif if (0 > ret){ printk("lirc_dev: error in module_unregister_chrdev: %d\n", ret); } else { dprintk("lirc_dev: module successfully unloaded\n"); }}#endif/* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- * Local variables: * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -