📄 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>#ifdef HAVE_LINUX_CONFIG_H#include <linux/config.h>#endif#include <linux/types.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/slab.h>#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)#include <linux/devfs_fs_kernel.h>#endif#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19)#include <linux/page-flags.h>#include <linux/mm.h>#endif#include <linux/proc_fs.h>#include <linux/poll.h>#include <linux/init.h>#include <asm/io.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"#include "shmpool.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 250#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/******************************************************************************/#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)voidfusion_sleep_on(wait_queue_head_t *q, struct semaphore *lock, signed long *timeout){ DEFINE_WAIT(wait); prepare_to_wait( q, &wait, TASK_INTERRUPTIBLE ); up( lock ); if (timeout) *timeout = schedule_timeout(*timeout); else schedule(); finish_wait( q, &wait );}#elsevoidfusion_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; 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 dispatch " "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 %10d\n", dev->stat.property_lease_purchase, dev->stat.property_cede, dev->stat.reactor_attach, dev->stat.reactor_detach, dev->stat.reactor_dispatch, 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; init_MUTEX( &dev->enter_lock ); init_waitqueue_head( &dev->enter_wait ); 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_shmpool_init (dev); if (ret) goto error_shmpool; 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_shmpool_deinit (dev);error_shmpool: 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_shmpool_deinit (dev); fusion_reactor_deinit (dev); fusion_property_deinit (dev); fusion_skirmish_deinit (dev); fusion_ref_deinit (dev); fusionee_deinit (dev); if (dev->shared_area) { ClearPageReserved( virt_to_page(dev->shared_area) ); free_page( dev->shared_area ); }}/******************************************************************************/static intfusion_open (struct inode *inode, struct file *file){ int ret; Fusionee *fusionee; int minor = iminor(inode); DEBUG( "fusion_open( %p, %d )\n", file, atomic_read(&file->f_count) ); 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); fusion_devs[minor]->index = minor; 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) { if (fusion_devs[minor]->fusionee.last_id) { up (&devs_lock); return -EBUSY; } } ret = fusionee_new (fusion_devs[minor], !!(file->f_flags & O_APPEND), &fusionee); 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 = fusionee; return 0;}static intfusion_release (struct inode *inode, struct file *file){ int minor = iminor(inode); Fusionee *fusionee = file->private_data; DEBUG( "fusion_release( %p, %d )\n", file, atomic_read(&file->f_count) ); fusionee_destroy (fusion_devs[minor], fusionee); 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 int#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)fusion_flush (struct file *file, fl_owner_t id)#elsefusion_flush (struct file *file)#endif{ Fusionee *fusionee = file->private_data; FusionDev *dev = fusion_devs[iminor(file->f_dentry->d_inode)]; (void) fusionee; DEBUG( "fusion_flush( %p, %d, 0x%08x %d )\n", file, atomic_read(&file->f_count), fusionee_id(fusionee), 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){ Fusionee *fusionee = file->private_data; FusionDev *dev = fusion_devs[iminor(file->f_dentry->d_inode)]; DEBUG( "fusion_read( %p, %d, %d )\n", file, atomic_read(&file->f_count), count ); return fusionee_get_messages (dev, fusionee, buf, count, !(file->f_flags & O_NONBLOCK));}static unsigned intfusion_poll (struct file *file, poll_table * wait){ Fusionee *fusionee = file->private_data; FusionDev *dev = fusion_devs[iminor(file->f_dentry->d_inode)];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -