/* * Copyright (C) 2011 Pan Ruochen * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. * * This program is distributed in the hope 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. * * Export read/write interfaces to MIPS watchlo/watchhi registers to * user space through proc file system. * */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #define __BUILD_READ_WATCH_FUNC(postfix) \ static int proc_read_watch ## postfix(struct seq_file *f, void *data) { \ seq_printf(f, "0x%08x\n", (unsigned int)read_c0_watch ## postfix()); \ return 0; \ } __BUILD_READ_WATCH_FUNC(lo0) __BUILD_READ_WATCH_FUNC(lo1) __BUILD_READ_WATCH_FUNC(lo2) __BUILD_READ_WATCH_FUNC(lo3) __BUILD_READ_WATCH_FUNC(hi0) __BUILD_READ_WATCH_FUNC(hi1) __BUILD_READ_WATCH_FUNC(hi2) __BUILD_READ_WATCH_FUNC(hi3) static int atohex(const char __user *buf, unsigned long count, unsigned long *val) { char tmp[12]; if( count >= 12 ) return -ENOMEM; if (copy_from_user(tmp, buf, count)) return -EFAULT; sscanf(tmp, "%x", val); return 0; } #define __BUILD_WRITE_WATCH_FUNC(postfix) \ static int proc_write_watch ## postfix( \ struct file *file, const char __user *buf, \ unsigned long count,void *data) { \ int ret; \ unsigned long val; \ if( (ret = atohex(buf, count, &val)) < 0 ) \ return ret; \ write_c0_watch ## postfix (val); \ return count; \ } __BUILD_WRITE_WATCH_FUNC(lo0) __BUILD_WRITE_WATCH_FUNC(lo1) __BUILD_WRITE_WATCH_FUNC(lo2) __BUILD_WRITE_WATCH_FUNC(lo3) __BUILD_WRITE_WATCH_FUNC(hi0) __BUILD_WRITE_WATCH_FUNC(hi1) __BUILD_WRITE_WATCH_FUNC(hi2) __BUILD_WRITE_WATCH_FUNC(hi3) #define __BUILD_READ_WRAPPER_WATCH_FUNC(postfix) \ static int read_proc_open_watch ## postfix(struct inode *inode, struct file *file) { \ return(single_open(file, proc_read_watch ## postfix, NULL)); \ } __BUILD_READ_WRAPPER_WATCH_FUNC(lo0) __BUILD_READ_WRAPPER_WATCH_FUNC(lo1) __BUILD_READ_WRAPPER_WATCH_FUNC(lo2) __BUILD_READ_WRAPPER_WATCH_FUNC(lo3) __BUILD_READ_WRAPPER_WATCH_FUNC(hi0) __BUILD_READ_WRAPPER_WATCH_FUNC(hi1) __BUILD_READ_WRAPPER_WATCH_FUNC(hi2) __BUILD_READ_WRAPPER_WATCH_FUNC(hi3) #define __BUILD_WRITE_WRAPPER_WATCH_FUNC(postfix) \ static ssize_t write_proc_watch ## postfix(struct file *file, const char __user * userbuf, size_t count, loff_t * off) { \ return proc_write_watch ## postfix(file, userbuf, count, NULL); \ } __BUILD_WRITE_WRAPPER_WATCH_FUNC(lo0) __BUILD_WRITE_WRAPPER_WATCH_FUNC(lo1) __BUILD_WRITE_WRAPPER_WATCH_FUNC(lo2) __BUILD_WRITE_WRAPPER_WATCH_FUNC(lo3) __BUILD_WRITE_WRAPPER_WATCH_FUNC(hi0) __BUILD_WRITE_WRAPPER_WATCH_FUNC(hi1) __BUILD_WRITE_WRAPPER_WATCH_FUNC(hi2) __BUILD_WRITE_WRAPPER_WATCH_FUNC(hi3) #define __BUILD_FOPS_PROC_WATCH_FUNC(postfix) \ static struct file_operations fops_proc_watch ## postfix = { \ .open = read_proc_open_watch ## postfix, \ .read = seq_read, \ .llseek = seq_lseek, \ .release = single_release, \ .write = write_proc_watch ## postfix, \ }; __BUILD_FOPS_PROC_WATCH_FUNC(lo0) __BUILD_FOPS_PROC_WATCH_FUNC(lo1) __BUILD_FOPS_PROC_WATCH_FUNC(lo2) __BUILD_FOPS_PROC_WATCH_FUNC(lo3) __BUILD_FOPS_PROC_WATCH_FUNC(hi0) __BUILD_FOPS_PROC_WATCH_FUNC(hi1) __BUILD_FOPS_PROC_WATCH_FUNC(hi2) __BUILD_FOPS_PROC_WATCH_FUNC(hi3) int __init mips_watch_proc_init(void) { struct proc_dir_entry *parent, *ent; const char *ent_names[] = { "watchlo0", "watchhi0", "watchlo1", "watchhi1", "watchlo2", "watchhi2", "watchlo3", "watchhi3", }; const struct file_operations *ent_fops_proc_funcs[] = { &fops_proc_watchlo0, &fops_proc_watchhi0, &fops_proc_watchlo1, &fops_proc_watchhi1, &fops_proc_watchlo2, &fops_proc_watchhi2, &fops_proc_watchlo3, &fops_proc_watchhi3, }; int i; parent = proc_mkdir("mips_watch", NULL); if( parent == NULL ) { printk(KERN_WARNING "Failed to register /proc/mips_watch\n"); return 0; } for(i = 0; i < 8; i++) { ent = proc_create_data(ent_names[i], 0644, parent, ent_fops_proc_funcs[i], NULL); if (ent == NULL) { printk(KERN_WARNING "Failed to register /proc/mips_watch/%s\n", ent_names[i]); return 0; } } return 0; } module_init(mips_watch_proc_init);