#include /* We're doing kernel work */ #include /* Specifically, a module */ #include #include #include #include #include /* For jiffies */ MODULE_LICENSE( "GPL" ); static __u16 *mmcrbase, *pio_fun, *pio_dir, *pio_dat; #define BUFSIZE 32 #define DMASK 0x1000; static int nsamp = HZ/60; /* want to sample as fast as possible for 1 period */ static int mper = 5; /* seconds per filtered datapoint */ static int verbose = 0; #define MAXSAMPLES HZ/2 MODULE_PARM( mper, "i" ); MODULE_PARM( nsamp, "i" ); MODULE_PARM( verbose, "i" ); /* * This timer is used to take N samples every M seconds. * * The sample results are stored in a buffer and checked for each read * of the /proc/pump file. */ static struct timer_list timer; static unsigned char sample_buf[MAXSAMPLES]; static int pump_state = 0; static void sample( unsigned long data ){ static int remaining_samples = 0; __u16 dat; int ntimeout = 1; int mtimeout = HZ*mper - nsamp*ntimeout; if ( remaining_samples ){ timer.expires = jiffies + ntimeout; remaining_samples--; dat = readw( pio_dat ) & DMASK; if ( dat == 0 ){ sample_buf[remaining_samples] = 1; } add_timer( &timer ); } else { int i; char buf[MAXSAMPLES]; pump_state = 0; for( i = 0; i < nsamp; i++ ){ pump_state += sample_buf[i]; buf[i] = sample_buf[i] + '0'; sample_buf[i] = 0; } buf[i] = '\0'; if ( (verbose==1 && pump_state) || (verbose>1) ){ printk( KERN_INFO "Sample buffer at tick (%ld) %s\n", jiffies, buf ); } /* long tick between samples */ remaining_samples = nsamp; timer.expires = jiffies + mtimeout; add_timer(&timer); } } static ssize_t pump_output( struct file *file, /* The file read */ char *buf, /* The buffer to put data to (in the * user segment) */ size_t len, /* The length of the buffer */ loff_t *offset) /* Offset in the file - ignore */ { char my_buffer[BUFSIZE]; static int finished = 0; int i; if ( finished ){ finished = 0; return 0; } if ( pump_state ){ len = sprintf( my_buffer, "on\n" ); } else { len = sprintf( my_buffer, "off\n" ); } for(i=0; i < len && my_buffer[i]; i++ ){ put_user( my_buffer[i], buf + i ); } finished = 1; return i; } static struct proc_dir_entry *pde; static int pump_permission(struct inode *inode, int op) { if (op == 4 || (op == 2 && current->euid == pde->uid)) return 0; /* If it's anything else, access is denied */ return -EACCES; } static int pump_open(struct inode *inode, struct file *file) { MOD_INC_USE_COUNT; return 0; } static int pump_close(struct inode *inode, struct file *file) { MOD_DEC_USE_COUNT; return 0; /* success */ } static struct file_operations file_ops = { NULL, /* module owner ??? */ NULL, /* llseek */ pump_output, /* "read" from the file */ NULL, /* "write" to the file */ NULL, /* readdir */ NULL, /* poll */ NULL, /* ioctl */ NULL, /* mmap */ pump_open, /* Somebody opened the file */ NULL, /* flush, added here in version 2.2 */ pump_close, /* release */ NULL, /* fsync */ NULL, /* fasync */ NULL, /* lock */ NULL, /* readv */ NULL, /* writev */ NULL, /* sendpage */ NULL /* get_unmapped_area */ }; static struct inode_operations inode_ops = { NULL, /* create */ NULL, /* lookup */ NULL, /* link */ NULL, /* unlink */ NULL, /* symlink */ NULL, /* mkdir */ NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ NULL, /* truncate */ pump_permission, /* check for permissions */ NULL, /* revalidate */ NULL, /* setattr */ NULL /* getattr */ }; static void start_timer( void ){ int ntimeout = 1; if ( verbose ){ printk( KERN_INFO " Starting timer (%dHZ) mper=%d, nsamp=%d\n", HZ, mper, nsamp ); } init_timer( &timer ); timer.expires = jiffies + ntimeout; timer.function = sample; timer.data = 0; add_timer( &timer ); } static int init() { if ( (pde = create_proc_entry( "pump", S_IFREG|S_IRUGO, &proc_root)) ){ unsigned long cbar = inl_p(0xfffc); __u16 fun, dir, dat; int n=0; pde->size = BUFSIZE; pde->proc_iops = &inode_ops; pde->proc_fops = &file_ops; if ( cbar & 0x80000000 ){ mmcrbase = (__u16 *)(cbar & 0x3FFFFFFF); } else { mmcrbase = (__u16 *)0xFFFEF000; } pio_fun = (__u16 *)((char *)mmcrbase + 0xc20 ); pio_fun = ioremap( (unsigned long)pio_fun ,2 ); pio_dir = (__u16 *)((char *)mmcrbase + 0xc2a ); pio_dir = ioremap( (unsigned long)pio_dir ,2 ); pio_dat = (__u16 *)((char *)mmcrbase + 0xc30 ); pio_dat = ioremap( (unsigned long)pio_dat ,2 ); /* * Make sure PIO12 is set as an input */ dir = readw( pio_dir ); fun = readw( pio_fun ); dat = readw( pio_dat ); dir &= ~DMASK; fun &= ~DMASK; writew( fun, pio_fun ); writew( dir, pio_dir ); /* * ensure that the passed parameters are still sensible */ if ( (nsamp == 0) || (nsamp >= MAXSAMPLES) ){ nsamp = MAXSAMPLES>>1; } while ( n < nsamp ){ sample_buf[n++] = 0; } start_timer(); return 0; } return -ENOMEM; } /* Cleanup - unregister our file from /proc */ static void cleanup() { iounmap( pio_fun ); iounmap( pio_dat ); iounmap( pio_dir ); del_timer( &timer ); remove_proc_entry(pde->name, &proc_root ); } module_init(init); module_exit(cleanup);