Messages in this thread | | | Date | Wed, 24 Apr 1996 21:45:01 +0200 (MET DST) | From | Barry Lagerweij <> | Subject | Re: writing a parallel port driver to support external hardware |
| |
Hi Richard,
On Tue, 23 Apr 1996, Richard A. Reitmeyer wrote:
> Some people here are in the process of building a small robot, and have > decided to use a parallel port interface because the hardware's > easier that way.
I've recently build a stepping motor device driver for Linux, which can be used as a loadable module. The delay part is an example of how *NOT* to program in a multitasking environment, but I needed a quick dirty hack, and usleep() didn't work the way I expected, so there it is.
I have two stepping motors directly attached to the parallel port, and I can control them by writing to /dev/motor, e.g. "0+010" will move motor 0 ten degrees clockwise, where "1=200" will move motor 1 to a fixed position (200).
Barry
/*------------------------------------------------------------ step motor ------------------------------------------------------------*/
#define __KERNEL__ #define MODULE
#include <linux/module.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/sched.h> #include <linux/ioport.h> #include <linux/mm.h> #include <linux/delay.h>
#include <asm/io.h> #include <asm/segment.h> #include <asm/system.h>
#define VER_MAJ 1 #define VER_MIN 0 #define NAME "motor"
int io_base = 0x278; int major = 60; int position[2];
const unsigned char steps[]= { 0x1,0x5,0x4,0x6,0x2,0xA,0x8,0x9 };
/* * the following code is needed for the loadable driver stuff */ static int do_open ( struct inode *inode, struct file *file ) { if (MINOR(inode->i_rdev) != 0) return(-ENODEV); if (MOD_IN_USE) return(-EBUSY); MOD_INC_USE_COUNT;
return(0); }
static int do_write ( struct inode *inode, struct file *file, const char *buf, int len ) { int rv; unsigned char motor_nr; int oldpos; int delta; int n,i; int step;
if (len != 5) return(-EINVAL); if ((rv = verify_area(VERIFY_READ, buf, len))) return(rv); motor_nr = get_fs_byte(buf) - '0'; if (motor_nr > 9) return(-EINVAL); oldpos = position[motor_nr]; i = ((get_fs_byte(buf+2)-'0')*100)+ ((get_fs_byte(buf+3)-'0')*10)+ (get_fs_byte(buf+4)-'0'); switch (get_fs_byte(buf+1)) { case '=' : delta = i - oldpos; break; case '-' : delta = -i; break; case '+' : delta = i; break; default : return(-EINVAL); } delta %= 400; if (delta > 200) { delta -= 400; } else { if (delta < -200) delta += 400; } if (oldpos + delta < -400) { delta += 400; } else { if (oldpos + delta > 400) { delta -= 400; } } step = ( delta < 0 ? -1 : +1 ); if (delta < 0) delta = -delta; for (i=0; i<delta; i++) { position[motor_nr] = oldpos; outb(steps[position[0]&7]+(steps[position[1]&7]<<4),io_base); for (n=0; n<500000; n++) { if (need_resched) schedule(); } oldpos += step; } position[motor_nr] = oldpos;
return(len); }
static void do_release ( struct inode *inode, struct file *file ) { MOD_DEC_USE_COUNT; }
static struct file_operations fops = { NULL, /* lseek */ NULL, /* read */ do_write, /* write */ NULL, /* readdir */ NULL, /* select */ NULL, /* ioctl */ NULL, /* mmap */ do_open, /* open */ do_release, /* release */ NULL, NULL, NULL, NULL };
int init_module ( void ) { printk("motor: driver at 0x%x version %d.%d\n", io_base,VER_MAJ,VER_MIN); if (check_region(io_base, 3) < 0) { printk("motor: Error: Cannot request I/O area\n"); return -1; } request_region(io_base, 3, NAME); if (register_chrdev(major, NAME, &fops)) { printk("motor: Error: Cannot register major number %d\n",major); return(-EIO); } position[0] = position[1] = 0; return(0); }
void cleanup_module ( void ) { printk("removing stepmotor driver\n"); if (MOD_IN_USE) { printk("motor: Warning: Device is busy, delaying driver removal\n"); } if (unregister_chrdev(major,NAME)) { printk("motor: Error: unregister_chrdev() failed\n"); } release_region(io_base,3); }
| |