!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/usr/src/linux-2.4.18-xfs-1.1/drivers/char/   drwxr-xr-x
Free 318.37 GB of 458.09 GB (69.5%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     pc110pad.c (19.15 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 *    Linux driver for the PC110 pad
 */
 
/**
 *     DOC: PC110 Digitizer Hardware
 *
 *    The pad provides triples of data. The first byte has
 *    0x80=bit 8 X, 0x01=bit 7 X, 0x08=bit 8 Y, 0x01=still down
 *    The second byte is bits 0-6 X
 *    The third is bits 0-6 Y
 *
 *    This is read internally and used to synthesize a stream of
 *    triples in the form expected from a PS/2 device. Specialist
 *    applications can choose to obtain the pad data in other formats
 *    including a debugging mode.
 *
 *    It would be good to add a joystick driver mode to this pad so
 *    that doom and other game playing are better. One possible approach
 *    would be to deactive the mouse mode while the joystick port is opened.
 */
 
/*
 *    History
 *
 *    0.0 1997-05-16 Alan Cox <alan@redhat.com> - Pad reader
 *    0.1 1997-05-19 Robin O'Leary <robin@acm.org> - PS/2 emulation
 *    0.2 1997-06-03 Robin O'Leary <robin@acm.org> - tap gesture
 *    0.3 1997-06-27 Alan Cox <alan@redhat.com> - 2.1 commit
 *    0.4 1997-11-09 Alan Cox <alan@redhat.com> - Single Unix VFS API changes
 *    0.5 2000-02-10 Alan Cox <alan@redhat.com> - 2.3.x cleanup, documentation
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/ptrace.h>
#include <linux/poll.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/smp_lock.h>
#include <linux/init.h>

#include <asm/signal.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/semaphore.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>

#include "pc110pad.h"


static struct pc110pad_params default_params = {
    mode:            PC110PAD_PS2,
    bounce_interval:    50 MS,
    tap_interval:        200 MS,
    irq:            10,
    io:            0x15E0,
};

static struct pc110pad_params current_params;


/* driver/filesystem interface management */
static wait_queue_head_t queue;
static struct fasync_struct *asyncptr;
static int active;    /* number of concurrent open()s */
static struct semaphore reader_lock;

/**
 *    wake_readers:
 *
 *    Take care of letting any waiting processes know that
 *    now would be a good time to do a read().  Called
 *    whenever a state transition occurs, real or synthetic. Also
 *    issue any SIGIO's to programs that use SIGIO on mice (eg
 *    Executor)
 */
 
static void wake_readers(void)
{
    wake_up_interruptible(&queue);
    kill_fasync(&asyncptr, SIGIO, POLL_IN);
}


/*****************************************************************************/
/*
 * Deal with the messy business of synthesizing button tap and drag
 * events.
 *
 * Exports:
 *    notify_pad_up_down()
 *        Must be called whenever debounced pad up/down state changes.
 *    button_pending
 *        Flag is set whenever read_button() has new values
 *        to return.
 *    read_button()
 *        Obtains the current synthetic mouse button state.
 */

/*
 * These keep track of up/down transitions needed to generate the
 * synthetic mouse button events.  While recent_transition is set,
 * up/down events cause transition_count to increment.  tap_timer
 * turns off the recent_transition flag and may cause some synthetic
 * up/down mouse events to be created by incrementing synthesize_tap.
 */
 
static int button_pending;
static int recent_transition;
static int transition_count;
static int synthesize_tap;
static void tap_timeout(unsigned long data);
static struct timer_list tap_timer = { function: tap_timeout };


/**
 * tap_timeout:
 * @data: Unused
 *
 * This callback goes off a short time after an up/down transition;
 * before it goes off, transitions will be considered part of a
 * single PS/2 event and counted in transition_count.  Once the
 * timeout occurs the recent_transition flag is cleared and
 * any synthetic mouse up/down events are generated.
 */
 
static void tap_timeout(unsigned long data)
{
    if(!recent_transition)
    {
        printk(KERN_ERR "pc110pad: tap_timeout but no recent transition!\n");
    }
    if( transition_count==2 || transition_count==4 || transition_count==6 )
    {
        synthesize_tap+=transition_count;
        button_pending = 1;
        wake_readers();
    }
    recent_transition=0;
}


/**
 * notify_pad_up_down:
 *
 * Called by the raw pad read routines when a (debounced) up/down
 * transition is detected.
 */
 
void notify_pad_up_down(void)
{
    if(recent_transition)
    {
        transition_count++;
    }
    else
    {
        transition_count=1;
        recent_transition=1;
    }
    mod_timer(&tap_timer, jiffies + current_params.tap_interval);

    /* changes to transition_count can cause reported button to change */
    button_pending = 1;
    wake_readers();
}

/**
 *    read_button:
 *    @b: pointer to the button status.
 *
 *    The actual button state depends on what we are seeing. We have to check
 *    for the tap gesture and also for dragging.
 */

static void read_button(int *b)
{
    if(synthesize_tap)
    {
        *b=--synthesize_tap & 1;
    }
    else
    {
        *b=(!recent_transition && transition_count==3);    /* drag */
    }
    button_pending=(synthesize_tap>0);
}


/*****************************************************************************/
/*
 * Read pad absolute co-ordinates and debounced up/down state.
 *
 * Exports:
 *    pad_irq()
 *        Function to be called whenever the pad signals
 *        that it has new data available.
 *    read_raw_pad()
 *        Returns the most current pad state.
 *    xy_pending
 *        Flag is set whenever read_raw_pad() has new values
 *        to return.
 * Imports:
 *    wake_readers()
 *        Called when movement occurs.
 *    notify_pad_up_down()
 *        Called when debounced up/down status changes.
 */

/*
 * These are up/down state and absolute co-ords read directly from pad 
 */

static int raw_data[3];
static int raw_data_count;
static int raw_x, raw_y;    /* most recent absolute co-ords read */
static int raw_down;        /* raw up/down state */
static int debounced_down;    /* up/down state after debounce processing */
static enum { NO_BOUNCE, JUST_GONE_UP, JUST_GONE_DOWN } bounce=NO_BOUNCE;
                /* set just after an up/down transition */
static int xy_pending;    /* set if new data have not yet been read */

/* 
 * Timer goes off a short while after an up/down transition and copies
 * the value of raw_down to debounced_down.
 */
 
static void bounce_timeout(unsigned long data);
static struct timer_list bounce_timer = { function: bounce_timeout };



/**
 * bounce_timeout:
 * @data: Unused
 *
 * No further up/down transitions happened within the
 * bounce period, so treat this as a genuine transition.
 */

static void bounce_timeout(unsigned long data)
{
    switch(bounce)
    {
        case NO_BOUNCE:
        {
            /*
             * Strange; the timer callback should only go off if
             * we were expecting to do bounce processing!
             */
            printk(KERN_WARNING "pc110pad, bounce_timeout: bounce flag not set!\n");
            break;
        }
        case JUST_GONE_UP:
        {
            /*
             * The last up we spotted really was an up, so set
             * debounced state the same as raw state.
             */
            bounce=NO_BOUNCE;
            if(debounced_down==raw_down)
            {
                printk(KERN_WARNING "pc110pad, bounce_timeout: raw already debounced!\n");
            }
            debounced_down=raw_down;

            notify_pad_up_down();
            break;
        }
        case JUST_GONE_DOWN:
        {
            /*
             * We don't debounce down events, but we still time
             * out soon after one occurs so we can avoid the (x,y)
             * skittering that sometimes happens.
             */
            bounce=NO_BOUNCE;
            break;
        }
    }
}


/**
 * pad_irq:
 * @irq: Interrupt number
 * @ptr: Unused
 * @regs: Unused
 *
 * Callback when pad's irq goes off; copies values in to raw_* globals;
 * initiates debounce processing. This isn't SMP safe however there are
 * no SMP machines with a PC110 touchpad on them.
 */
 
static void pad_irq(int irq, void *ptr, struct pt_regs *regs)
{

    /* Obtain byte from pad and prime for next byte */
    {
        int value=inb_p(current_params.io);
        int handshake=inb_p(current_params.io+2);
        outb_p(handshake | 1, current_params.io+2);
        outb_p(handshake &~1, current_params.io+2);
        inb_p(0x64);

        raw_data[raw_data_count++]=value;
    }

    if(raw_data_count==3)
    {
        int new_down=raw_data[0]&0x01;
        int new_x=raw_data[1];
        int new_y=raw_data[2];
        if(raw_data[0]&0x10) new_x+=128;
        if(raw_data[0]&0x80) new_x+=256;
        if(raw_data[0]&0x08) new_y+=128;

        if( (raw_x!=new_x) || (raw_y!=new_y) )
        {
            raw_x=new_x;
            raw_y=new_y;
            xy_pending=1;
        }

        if(new_down != raw_down)
        {
            /* Down state has changed.  raw_down always holds
             * the most recently observed state.
             */
            raw_down=new_down;

            /* Forget any earlier bounce processing */
            if(bounce)
            {
                del_timer(&bounce_timer);
                bounce=NO_BOUNCE;
            }

            if(new_down)
            {
                if(debounced_down)
                {
                    /* pad gone down, but we were reporting
                     * it down anyway because we suspected
                     * (correctly) that the last up was just
                     * a bounce
                     */
                }
                else
                {
                    bounce=JUST_GONE_DOWN;
                    mod_timer(&bounce_timer,
                        jiffies+current_params.bounce_interval);
                    /* start new stroke/tap */
                    debounced_down=new_down;
                    notify_pad_up_down();
                }
            }
            else /* just gone up */
            {
                if(recent_transition)
                {
                    /* early bounces are probably part of
                     * a multi-tap gesture, so process
                     * immediately
                     */
                    debounced_down=new_down;
                    notify_pad_up_down();
                }
                else
                {
                    /* don't trust it yet */
                    bounce=JUST_GONE_UP;
                    mod_timer(&bounce_timer,
                        jiffies+current_params.bounce_interval);
                }
            }
        }
        wake_readers();
        raw_data_count=0;
    }
}

/**
 *    read_raw_pad:
 *    @down: set if the pen is down
 *    @debounced: set if the debounced pen position is down
 *    @x: X position
 *    @y: Y position
 *
 *    Retrieve the data saved by the interrupt handler and indicate we
 *    have no more pending XY to do. 
 *
 *    FIXME: We should switch to a spinlock for this.
 */

static void read_raw_pad(int *down, int *debounced, int *x, int *y)
{
    disable_irq(current_params.irq);
    {
        *down=raw_down;
        *debounced=debounced_down;
        *x=raw_x;
        *y=raw_y;
        xy_pending = 0;
    }
    enable_irq(current_params.irq);
}

/*****************************************************************************/
/*
 * Filesystem interface
 */

/* 
 * Read returns byte triples, so we need to keep track of
 * how much of a triple has been read.  This is shared across
 * all processes which have this device open---not that anything
 * will make much sense in that case.
 */
static int read_bytes[3];
static int read_byte_count;

/**
 *    sample_raw:
 *    @d: sample buffer
 *
 *    Retrieve a triple of sample data. 
 */


static void sample_raw(int d[3])
{
    d[0]=raw_data[0];
    d[1]=raw_data[1];
    d[2]=raw_data[2];
}

/**
 *    sample_rare:
 *    @d: sample buffer
 *
 *    Retrieve a triple of sample data and sanitize it. We do the needed
 *    scaling and masking to get the current status.
 */


static void sample_rare(int d[3])
{
    int thisd, thisdd, thisx, thisy;

    read_raw_pad(&thisd, &thisdd, &thisx, &thisy);

    d[0]=(thisd?0x80:0)
       | (thisx/256)<<4
       | (thisdd?0x08:0)
       | (thisy/256)
    ;
    d[1]=thisx%256;
    d[2]=thisy%256;
}

/**
 *    sample_debug:
 *    @d: sample buffer
 *
 *    Retrieve a triple of sample data and mix it up with the state 
 *    information in the gesture parser. Not useful for normal users but
 *    handy when debugging
 */

static void sample_debug(int d[3])
{
    int thisd, thisdd, thisx, thisy;
    int b;
    unsigned long flags;
    
    save_flags(flags);
    cli();
    read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
    d[0]=(thisd?0x80:0) | (thisdd?0x40:0) | bounce;
    d[1]=(recent_transition?0x80:0)+transition_count;
    read_button(&b);
    d[2]=(synthesize_tap<<4) | (b?0x01:0);
    restore_flags(flags);
}

/**
 *    sample_ps2:
 *    @d: sample buffer
 *
 *    Retrieve a triple of sample data and turn the debounced tap and
 *    stroke information into what appears to be a PS/2 mouse. This means
 *    the PC110 pad needs no funny application side support.
 */


static void sample_ps2(int d[3])
{
    static int lastx, lasty, lastd;

    int thisd, thisdd, thisx, thisy;
    int dx, dy, b;

    /*
     * Obtain the current mouse parameters and limit as appropriate for
     * the return data format.  Interrupts are only disabled while 
     * obtaining the parameters, NOT during the puts_fs_byte() calls,
     * so paging in put_user() does not affect mouse tracking.
     */
    read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
    read_button(&b);

    /* Now compare with previous readings.  Note that we use the
     * raw down flag rather than the debounced one.
     */
    if( (thisd && !lastd) /* new stroke */
     || (bounce!=NO_BOUNCE) )
    {
        dx=0;
        dy=0;
    }
    else
    {
        dx =  (thisx-lastx);
        dy = -(thisy-lasty);
    }
    lastx=thisx;
    lasty=thisy;
    lastd=thisd;

/*
    d[0]= ((dy<0)?0x20:0)
        | ((dx<0)?0x10:0)
        | 0x08
        | (b? 0x01:0x00)
    ;
*/
    d[0]= ((dy<0)?0x20:0)
        | ((dx<0)?0x10:0)
        | (b? 0x00:0x08)
    ;
    d[1]=dx;
    d[2]=dy;
}


/**
 *    fasync_pad:
 *    @fd:    file number for the file 
 *    @filp:    file handle
 *    @on:    1 to add, 0 to remove a notifier
 *
 *    Update the queue of asynchronous event notifiers. We can use the
 *    same helper the mice do and that does almost everything we need.
 */
 
static int fasync_pad(int fd, struct file *filp, int on)
{
    int retval;

    retval = fasync_helper(fd, filp, on, &asyncptr);
    if (retval < 0)
        return retval;
    return 0;
}


/**
 *    close_pad:
 *    @inode: inode of pad
 *    @file: file handle to pad
 *
 *    Close access to the pad. We turn the pad power off if this is the
 *    last user of the pad. I've not actually measured the power draw but
 *    the DOS driver is careful to do this so we follow suit.
 */
 
static int close_pad(struct inode * inode, struct file * file)
{
    lock_kernel();
    fasync_pad(-1, file, 0);
    if (!--active)
        outb(0x30, current_params.io+2);  /* switch off digitiser */
    unlock_kernel();
    return 0;
}


/**
 *    open_pad:
 *    @inode: inode of pad
 *    @file: file handle to pad
 *
 *    Open access to the pad. We turn the pad off first (we turned it off
 *    on close but if this is the first open after a crash the state is
 *    indeterminate). The device has a small fifo so we empty that before
 *    we kick it back into action.
 */
 
static int open_pad(struct inode * inode, struct file * file)
{
    unsigned long flags;
    
    if (active++)
        return 0;

    save_flags(flags);
    cli();
    outb(0x30, current_params.io+2);    /* switch off digitiser */
    pad_irq(0,0,0);        /* read to flush any pending bytes */
    pad_irq(0,0,0);        /* read to flush any pending bytes */
    pad_irq(0,0,0);        /* read to flush any pending bytes */
    outb(0x38, current_params.io+2);    /* switch on digitiser */
    current_params = default_params;
    raw_data_count=0;        /* re-sync input byte counter */
    read_byte_count=0;        /* re-sync output byte counter */
    button_pending=0;
    recent_transition=0;
    transition_count=0;
    synthesize_tap=0;
    del_timer(&bounce_timer);
    del_timer(&tap_timer);
    restore_flags(flags);

    return 0;
}


/**
 *    write_pad:
 *    @file: File handle to the pad
 *    @buffer: Unused
 *    @count: Unused
 *    @ppos: Unused
 *
 *    Writes are disallowed. A true PS/2 mouse lets you write stuff. Everyone
 *    seems happy with this and not faking the write modes.
 */

static ssize_t write_pad(struct file * file, const char * buffer, size_t count, loff_t *ppos)
{
    return -EINVAL;
}


/*
 *    new_sample:
 *    @d: sample buffer
 *
 *    Fetch a new sample according the current mouse mode the pad is 
 *    using.
 */
 
void new_sample(int d[3])
{
    switch(current_params.mode)
    {
        case PC110PAD_RAW:    sample_raw(d);        break;
        case PC110PAD_RARE:    sample_rare(d);        break;
        case PC110PAD_DEBUG:    sample_debug(d);    break;
        case PC110PAD_PS2:    sample_ps2(d);        break;
    }
}


/**
 * read_pad:
 * @file: File handle to pad
 * @buffer: Target for the mouse data
 * @count: Buffer length
 * @ppos: Offset (unused)
 *
 * Read data from the pad. We use the reader_lock to avoid mess when there are
 * two readers. This shouldnt be happening anyway but we play safe.
 */
 
static ssize_t read_pad(struct file * file, char * buffer, size_t count, loff_t *ppos)
{
    int r;

    down(&reader_lock);
    for(r=0; r<count; r++)
    {
        if(!read_byte_count)
            new_sample(read_bytes);
        if(put_user(read_bytes[read_byte_count], buffer+r))
        {
            r = -EFAULT;
            break;
        }
        read_byte_count = (read_byte_count+1)%3;
    }
    up(&reader_lock);
    return r;
}


/**
 * pad_poll:
 * @file: File of the pad device
 * @wait: Poll table
 *
 * The pad is ready to read if there is a button or any position change
 * pending in the queue. The reading and interrupt routines maintain the
 * required state for us and do needed wakeups.
 */

static unsigned int pad_poll(struct file *file, poll_table * wait)
{
    poll_wait(file, &queue, wait);
        if(button_pending || xy_pending)
        return POLLIN | POLLRDNORM;
    return 0;
}


/**
 *    pad_ioctl;
 *    @inode: Inode of the pad
 *    @file: File handle to the pad
 *    @cmd: Ioctl command
 *    @arg: Argument pointer
 *
 *    The PC110 pad supports two ioctls both of which use the pc110pad_params
 *    structure. GETP queries the current pad status. SETP changes the pad
 *    configuration. Changing configuration during normal mouse operations
 *    may give momentarily odd results as things like tap gesture state
 *    may be lost.
 */
 
static int pad_ioctl(struct inode *inode, struct file * file,
    unsigned int cmd, unsigned long arg)
{
    struct pc110pad_params new;

    if (!inode)
        return -EINVAL;
        
    switch (cmd) {
    case PC110PADIOCGETP:
        new = current_params;
        if(copy_to_user((void *)arg, &new, sizeof(new)))
            return -EFAULT;
        return 0;

    case PC110PADIOCSETP:
        if(copy_from_user(&new, (void *)arg, sizeof(new)))
            return -EFAULT;

        if( (new.mode<PC110PAD_RAW)
         || (new.mode>PC110PAD_PS2)
         || (new.bounce_interval<0)
         || (new.tap_interval<0)
        )
            return -EINVAL;

        current_params.mode    = new.mode;
        current_params.bounce_interval    = new.bounce_interval;
        current_params.tap_interval    = new.tap_interval;
        return 0;
    }
    return -ENOTTY;
}


static struct file_operations pad_fops = {
    owner:        THIS_MODULE,
    read:        read_pad,
    write:        write_pad,
    poll:        pad_poll,
    ioctl:        pad_ioctl,
    open:        open_pad,
    release:    close_pad,
    fasync:        fasync_pad,
};


static struct miscdevice pc110_pad = {
    minor:        PC110PAD_MINOR,
    name:        "pc110 pad",
    fops:        &pad_fops,
};


/**
 *    pc110pad_init_driver:
 *
 *    We configure the pad with the default parameters (that is PS/2 
 *    emulation mode. We then claim the needed I/O and interrupt resources.
 *    Finally as a matter of paranoia we turn the pad off until we are
 *    asked to open it by an application.
 */

static char banner[] __initdata = KERN_INFO "PC110 digitizer pad at 0x%X, irq %d.\n";

static int __init pc110pad_init_driver(void)
{
    init_MUTEX(&reader_lock);
    current_params = default_params;

    if (request_irq(current_params.irq, pad_irq, 0, "pc110pad", 0)) {
        printk(KERN_ERR "pc110pad: Unable to get IRQ.\n");
        return -EBUSY;
    }
    if (!request_region(current_params.io, 4, "pc110pad"))    {
        printk(KERN_ERR "pc110pad: I/O area in use.\n");
        free_irq(current_params.irq,0);
        return -EBUSY;
    }
    init_waitqueue_head(&queue);
    printk(banner, current_params.io, current_params.irq);
    misc_register(&pc110_pad);
    outb(0x30, current_params.io+2);    /* switch off digitiser */
    return 0;
}

/*
 *    pc110pad_exit_driver:
 *
 *    Free the resources we acquired when the module was loaded. We also
 *    turn the pad off to be sure we don't leave it using power.
 */

static void __exit pc110pad_exit_driver(void)
{
    outb(0x30, current_params.io+2);    /* switch off digitiser */
    if (current_params.irq)
        free_irq(current_params.irq, 0);
    current_params.irq = 0;
    release_region(current_params.io, 4);
    misc_deregister(&pc110_pad);
}

module_init(pc110pad_init_driver);
module_exit(pc110pad_exit_driver);

MODULE_AUTHOR("Alan Cox, Robin O'Leary");
MODULE_DESCRIPTION("Driver for the touchpad on the IBM PC110 palmtop");
MODULE_LICENSE("GPL");

EXPORT_NO_SYMBOLS;

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0237 ]--