📄 fusiondev.c
字号:
/* * Fusion Kernel Module * * (c) Copyright 2002-2003 Convergence GmbH * * Written by Denis Oliver Kropp <dok@directfb.org> * * * 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. */#include <linux/version.h>#include <linux/module.h>#include <linux/config.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/slab.h>#include <linux/devfs_fs_kernel.h>#include <linux/proc_fs.h>#include <linux/poll.h>#include <linux/init.h>#include <asm/uaccess.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 2)#include <linux/device.h>#endif#include <linux/fusion.h>#include "call.h"#include "fusiondev.h"#include "fusionee.h"#include "property.h"#include "reactor.h"#include "ref.h"#include "skirmish.h"#if 0#define DEBUG(x...) printk (KERN_DEBUG "Fusion: " x)#else#define DEBUG(x...) do {} while (0)#endif#ifndef FUSION_MAJOR#define FUSION_MAJOR 252#endifMODULE_LICENSE("GPL");MODULE_AUTHOR("Denis Oliver Kropp <dok@directfb.org>");struct proc_dir_entry *proc_fusion_dir;#define NUM_MINORS 8static FusionDev *fusion_devs[NUM_MINORS] = { 0 };static DECLARE_MUTEX(devs_lock);#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)static devfs_handle_t devfs_handles[NUM_MINORS];static inline unsigned iminor(struct inode *inode){ return MINOR(inode->i_rdev);}#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 2)#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)static struct class *fusion_class;#elsestatic struct class_simple *fusion_class;#endif#endif/******************************************************************************/voidfusion_sleep_on(wait_queue_head_t *q, struct semaphore *lock, signed long *timeout){ wait_queue_t wait; init_waitqueue_entry (&wait, current); current->state = TASK_INTERRUPTIBLE;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) spin_lock (&q->lock); __add_wait_queue (q, &wait); spin_unlock (&q->lock); up (lock); if (timeout) *timeout = schedule_timeout(*timeout); else schedule(); spin_lock (&q->lock); __remove_wait_queue (q, &wait); spin_unlock (&q->lock);#else write_lock (&q->lock); __add_wait_queue (q, &wait); write_unlock (&q->lock); up (lock); if (timeout) *timeout = schedule_timeout(*timeout); else schedule(); write_lock (&q->lock); __remove_wait_queue (q, &wait); write_unlock (&q->lock);#endif}/******************************************************************************/static intfusiondev_stat_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *private){ FusionDev *dev = private; int written = 0; written += snprintf( buf, len, "lease/purchase cede attach detach " "ref up ref down prevail/swoop dismiss\n" ); if (written < offset) { offset -= written; written = 0; } if (written < len) { written += snprintf( buf+written, len - written, "%10d %10d %10d %10d %10d %10d %10d %10d\n", dev->stat.property_lease_purchase, dev->stat.property_cede, dev->stat.reactor_attach, dev->stat.reactor_detach, dev->stat.ref_up, dev->stat.ref_down, dev->stat.skirmish_prevail_swoop, dev->stat.skirmish_dismiss ); if (written < offset) { offset -= written; written = 0; } } *start = buf + offset; written -= offset; if (written > len) { *eof = 0; return len; } *eof = 1; return(written<0) ? 0 : written;}/******************************************************************************/static intfusiondev_init (FusionDev *dev){ int ret; ret = fusionee_init (dev); if (ret) goto error_fusionee; ret = fusion_ref_init (dev); if (ret) goto error_ref; ret = fusion_skirmish_init (dev); if (ret) goto error_skirmish; ret = fusion_property_init (dev); if (ret) goto error_property; ret = fusion_reactor_init (dev); if (ret) goto error_reactor; ret = fusion_call_init (dev); if (ret) goto error_call; create_proc_read_entry("stat", 0, dev->proc_dir, fusiondev_stat_read_proc, dev); return 0;error_call: fusion_reactor_deinit (dev);error_reactor: fusion_property_deinit (dev);error_property: fusion_skirmish_deinit (dev);error_skirmish: fusion_ref_deinit (dev);error_ref: fusionee_deinit (dev);error_fusionee: return ret;}static voidfusiondev_deinit (FusionDev *dev){ remove_proc_entry ("stat", dev->proc_dir); fusion_call_deinit (dev); fusion_reactor_deinit (dev); fusion_property_deinit (dev); fusion_skirmish_deinit (dev); fusion_ref_deinit (dev); fusionee_deinit (dev);}/******************************************************************************/static intfusion_open (struct inode *inode, struct file *file){ int ret; int fusion_id; int minor = iminor(inode); DEBUG( "fusion_open\n" ); if (down_interruptible (&devs_lock)) return -EINTR; if (!fusion_devs[minor]) { char buf[4]; fusion_devs[minor] = kmalloc (sizeof(FusionDev), GFP_KERNEL); if (!fusion_devs[minor]) { up (&devs_lock); return -ENOMEM; } memset (fusion_devs[minor], 0, sizeof(FusionDev)); snprintf (buf, 4, "%d", minor); fusion_devs[minor]->proc_dir = proc_mkdir (buf, proc_fusion_dir); ret = fusiondev_init (fusion_devs[minor]); if (ret) { remove_proc_entry (buf, proc_fusion_dir); kfree (fusion_devs[minor]); fusion_devs[minor] = NULL; up (&devs_lock); return ret; } } else if (file->f_flags & O_EXCL) { up (&devs_lock); return -EBUSY; } ret = fusionee_new (fusion_devs[minor], &fusion_id); if (ret) { if (!fusion_devs[minor]->refs) { fusiondev_deinit (fusion_devs[minor]); remove_proc_entry (fusion_devs[minor]->proc_dir->name, proc_fusion_dir); kfree (fusion_devs[minor]); fusion_devs[minor] = NULL; } up (&devs_lock); return ret; } fusion_devs[minor]->refs++; up (&devs_lock); file->private_data = (void*) fusion_id; return 0;}static intfusion_release (struct inode *inode, struct file *file){ int ret; int minor = iminor(inode); int fusion_id = (int) file->private_data; DEBUG( "fusion_release\n" ); ret = fusionee_destroy (fusion_devs[minor], fusion_id); if (ret) return ret; down (&devs_lock); if (! --fusion_devs[minor]->refs) { fusiondev_deinit (fusion_devs[minor]); remove_proc_entry (fusion_devs[minor]->proc_dir->name, proc_fusion_dir); kfree (fusion_devs[minor]); fusion_devs[minor] = NULL; } up (&devs_lock); return 0;}static intfusion_flush (struct file *file){ int fusion_id = (int) file->private_data; FusionDev *dev = fusion_devs[iminor(file->f_dentry->d_inode)]; (void) fusion_id; DEBUG( "fusion_flush (0x%08x %d)\n", fusion_id, current->pid ); if (current->flags & PF_EXITING) fusion_skirmish_dismiss_all_from_pid (dev, current->pid); return 0;}static ssize_tfusion_read (struct file *file, char *buf, size_t count, loff_t *ppos){ int fusion_id = (int) file->private_data; FusionDev *dev = fusion_devs[iminor(file->f_dentry->d_inode)]; DEBUG( "fusion_read (%d)\n", count ); return fusionee_get_messages (dev, fusion_id, buf, count, !(file->f_flags & O_NONBLOCK));}static unsigned intfusion_poll (struct file *file, poll_table * wait){ int fusion_id = (int) file->private_data; FusionDev *dev = fusion_devs[iminor(file->f_dentry->d_inode)]; DEBUG( "fusion_poll\n" ); return fusionee_poll (dev, fusion_id, file, wait);}static intlounge_ioctl (FusionDev *dev, int fusion_id, unsigned int cmd, unsigned long arg){ int ret; FusionEnter enter; FusionKill kill; FusionEntryInfo info; switch (_IOC_NR(cmd)) { case _IOC_NR(FUSION_ENTER): if (copy_from_user (&enter, (FusionEnter*) arg, sizeof(enter))) return -EFAULT; if (enter.api.major != FUSION_API_MAJOR || enter.api.minor > FUSION_API_MINOR) return -ENOPROTOOPT; enter.fusion_id = fusion_id; if (copy_to_user ((FusionEnter*) arg, &enter, sizeof(enter))) return -EFAULT; return 0; case _IOC_NR(FUSION_KILL): if (copy_from_user (&kill, (FusionKill*) arg, sizeof(kill))) return -EFAULT; return fusionee_kill (dev, fusion_id, kill.fusion_id, kill.signal, kill.timeout_ms); case _IOC_NR(FUSION_ENTRY_SET_INFO): if (copy_from_user (&info, (FusionEntryInfo*) arg, sizeof(info))) return -EFAULT; switch (info.type) { case FT_SKIRMISH: return fusion_entry_set_info (&dev->skirmish, &info); case FT_PROPERTY: return fusion_entry_set_info (&dev->properties, &info); case FT_REACTOR: return fusion_entry_set_info (&dev->reactor, &info); default: return -ENOSYS; } case _IOC_NR(FUSION_ENTRY_GET_INFO): if (copy_from_user (&info, (FusionEntryInfo*) arg, sizeof(info))) return -EFAULT; switch (info.type) { case FT_SKIRMISH: ret = fusion_entry_get_info (&dev->skirmish, &info); break; case FT_PROPERTY: ret = fusion_entry_get_info (&dev->properties, &info); break; case FT_REACTOR: ret = fusion_entry_get_info (&dev->reactor, &info); break; default: return -ENOSYS; } if (ret) return ret; if (copy_to_user ((FusionEntryInfo*) arg, &info, sizeof(info))) return -EFAULT; return 0; } return -ENOSYS;}static intmessaging_ioctl (FusionDev *dev, int fusion_id, unsigned int cmd, unsigned long arg){ FusionSendMessage send; switch (_IOC_NR(cmd)) { case _IOC_NR(FUSION_SEND_MESSAGE): if (copy_from_user (&send, (FusionSendMessage*) arg, sizeof(send))) return -EFAULT; if (send.msg_size <= 0) return -EINVAL; /* message data > 64k should be stored in shared memory */ if (send.msg_size > 0x10000) return -EMSGSIZE; return fusionee_send_message (dev, fusion_id, send.fusion_id, FMT_SEND, send.msg_id, send.msg_size, send.msg_data); } return -ENOSYS;}static intcall_ioctl (FusionDev *dev, int fusion_id, unsigned int cmd, unsigned long arg){ int id; int ret;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -