lkml.org 
[lkml]   [1996]   [Apr]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: 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);
    }



    \
     
     \ /
      Last update: 2005-03-22 13:36    [W:0.024 / U:90.292 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site