📄 pc110pad.c
字号:
*/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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -