📄 ibmasmfs.c
字号:
/* * IBM ASM Service Processor Device Driver * * 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. * * Copyright (C) IBM Corporation, 2004 * * Author: Max Asb鯿k <amax@us.ibm.com> * *//* * Parts of this code are based on an article by Jonathan Corbet * that appeared in Linux Weekly News. *//* * The IBMASM file virtual filesystem. It creates the following hierarchy * dymamically when mounted from user space: * * /ibmasm * |-- 0 * | |-- command * | |-- event * | |-- reverse_heartbeat * | `-- remote_video * | |-- depth * | |-- height * | `-- width * . * . * . * `-- n * |-- command * |-- event * |-- reverse_heartbeat * `-- remote_video * |-- depth * |-- height * `-- width * * For each service processor the following files are created: * * command: execute dot commands * write: execute a dot command on the service processor * read: return the result of a previously executed dot command * * events: listen for service processor events * read: sleep (interruptible) until an event occurs * write: wakeup sleeping event listener * * reverse_heartbeat: send a heartbeat to the service processor * read: sleep (interruptible) until the reverse heartbeat fails * write: wakeup sleeping heartbeat listener * * remote_video/width * remote_video/height * remote_video/width: control remote display settings * write: set value * read: read value */#include <linux/fs.h>#include <linux/pagemap.h>#include <asm/uaccess.h>#include <asm/io.h>#include "ibmasm.h"#include "remote.h"#include "dot_command.h"#define IBMASMFS_MAGIC 0x66726f67static LIST_HEAD(service_processors);static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode);static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root);static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent);static struct super_block *ibmasmfs_get_super(struct file_system_type *fst, int flags, const char *name, void *data){ return get_sb_single(fst, flags, data, ibmasmfs_fill_super);}static struct super_operations ibmasmfs_s_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode,};static struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations;static struct file_system_type ibmasmfs_type = { .owner = THIS_MODULE, .name = "ibmasmfs", .get_sb = ibmasmfs_get_super, .kill_sb = kill_litter_super,};static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent){ struct inode *root; struct dentry *root_dentry; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = IBMASMFS_MAGIC; sb->s_op = &ibmasmfs_s_ops; sb->s_time_gran = 1; root = ibmasmfs_make_inode (sb, S_IFDIR | 0500); if (!root) return -ENOMEM; root->i_op = &simple_dir_inode_operations; root->i_fop = ibmasmfs_dir_ops; root_dentry = d_alloc_root(root); if (!root_dentry) { iput(root); return -ENOMEM; } sb->s_root = root_dentry; ibmasmfs_create_files(sb, root_dentry); return 0;}static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode){ struct inode *ret = new_inode(sb); if (ret) { ret->i_mode = mode; ret->i_uid = ret->i_gid = 0; ret->i_blksize = PAGE_CACHE_SIZE; ret->i_blocks = 0; ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; } return ret;}static struct dentry *ibmasmfs_create_file (struct super_block *sb, struct dentry *parent, const char *name, struct file_operations *fops, void *data, int mode){ struct dentry *dentry; struct inode *inode; dentry = d_alloc_name(parent, name); if (!dentry) return NULL; inode = ibmasmfs_make_inode(sb, S_IFREG | mode); if (!inode) { dput(dentry); return NULL; } inode->i_fop = fops; inode->u.generic_ip = data; d_add(dentry, inode); return dentry;}static struct dentry *ibmasmfs_create_dir (struct super_block *sb, struct dentry *parent, const char *name){ struct dentry *dentry; struct inode *inode; dentry = d_alloc_name(parent, name); if (!dentry) return NULL; inode = ibmasmfs_make_inode(sb, S_IFDIR | 0500); if (!inode) { dput(dentry); return NULL; } inode->i_op = &simple_dir_inode_operations; inode->i_fop = ibmasmfs_dir_ops; d_add(dentry, inode); return dentry;}int ibmasmfs_register(void){ return register_filesystem(&ibmasmfs_type);}void ibmasmfs_unregister(void){ unregister_filesystem(&ibmasmfs_type);}void ibmasmfs_add_sp(struct service_processor *sp){ list_add(&sp->node, &service_processors);}/* struct to save state between command file operations */struct ibmasmfs_command_data { struct service_processor *sp; struct command *command;};/* struct to save state between event file operations */struct ibmasmfs_event_data { struct service_processor *sp; struct event_reader reader; int active;};/* struct to save state between reverse heartbeat file operations */struct ibmasmfs_heartbeat_data { struct service_processor *sp; struct reverse_heartbeat heartbeat; int active;};static int command_file_open(struct inode *inode, struct file *file){ struct ibmasmfs_command_data *command_data; if (!inode->u.generic_ip) return -ENODEV; command_data = kmalloc(sizeof(struct ibmasmfs_command_data), GFP_KERNEL); if (!command_data) return -ENOMEM; command_data->command = NULL; command_data->sp = inode->u.generic_ip; file->private_data = command_data; return 0;}static int command_file_close(struct inode *inode, struct file *file){ struct ibmasmfs_command_data *command_data = file->private_data; if (command_data->command) command_put(command_data->command); kfree(command_data); return 0;}static ssize_t command_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset){ struct ibmasmfs_command_data *command_data = file->private_data; struct command *cmd; int len; unsigned long flags; if (*offset < 0) return -EINVAL; if (count == 0 || count > IBMASM_CMD_MAX_BUFFER_SIZE) return 0; if (*offset != 0) return 0; spin_lock_irqsave(&command_data->sp->lock, flags); cmd = command_data->command; if (cmd == NULL) { spin_unlock_irqrestore(&command_data->sp->lock, flags); return 0; } command_data->command = NULL; spin_unlock_irqrestore(&command_data->sp->lock, flags); if (cmd->status != IBMASM_CMD_COMPLETE) { command_put(cmd); return -EIO; } len = min(count, cmd->buffer_size); if (copy_to_user(buf, cmd->buffer, len)) { command_put(cmd); return -EFAULT; } command_put(cmd); return len;}static ssize_t command_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset){ struct ibmasmfs_command_data *command_data = file->private_data; struct command *cmd; unsigned long flags; if (*offset < 0) return -EINVAL; if (count == 0 || count > IBMASM_CMD_MAX_BUFFER_SIZE) return 0; if (*offset != 0) return 0; /* commands are executed sequentially, only one command at a time */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -