pc110pad.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:19k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Linux driver for the PC110 pad
  3.  */
  4.  
  5. /**
  6.  *  DOC: PC110 Digitizer Hardware
  7.  *
  8.  * The pad provides triples of data. The first byte has
  9.  * 0x80=bit 8 X, 0x01=bit 7 X, 0x08=bit 8 Y, 0x01=still down
  10.  * The second byte is bits 0-6 X
  11.  * The third is bits 0-6 Y
  12.  *
  13.  * This is read internally and used to synthesize a stream of
  14.  * triples in the form expected from a PS/2 device. Specialist
  15.  * applications can choose to obtain the pad data in other formats
  16.  * including a debugging mode.
  17.  *
  18.  * It would be good to add a joystick driver mode to this pad so
  19.  * that doom and other game playing are better. One possible approach
  20.  * would be to deactive the mouse mode while the joystick port is opened.
  21.  */
  22.  
  23. /*
  24.  * History
  25.  *
  26.  * 0.0 1997-05-16 Alan Cox <alan@redhat.com> - Pad reader
  27.  * 0.1 1997-05-19 Robin O'Leary <robin@acm.org> - PS/2 emulation
  28.  * 0.2 1997-06-03 Robin O'Leary <robin@acm.org> - tap gesture
  29.  * 0.3 1997-06-27 Alan Cox <alan@redhat.com> - 2.1 commit
  30.  * 0.4 1997-11-09 Alan Cox <alan@redhat.com> - Single Unix VFS API changes
  31.  * 0.5 2000-02-10 Alan Cox <alan@redhat.com> - 2.3.x cleanup, documentation
  32.  */
  33. #include <linux/module.h>
  34. #include <linux/kernel.h>
  35. #include <linux/signal.h>
  36. #include <linux/errno.h>
  37. #include <linux/mm.h>
  38. #include <linux/miscdevice.h>
  39. #include <linux/ptrace.h>
  40. #include <linux/poll.h>
  41. #include <linux/ioport.h>
  42. #include <linux/interrupt.h>
  43. #include <linux/smp_lock.h>
  44. #include <linux/init.h>
  45. #include <asm/signal.h>
  46. #include <asm/io.h>
  47. #include <asm/irq.h>
  48. #include <asm/semaphore.h>
  49. #include <linux/spinlock.h>
  50. #include <asm/uaccess.h>
  51. #include "pc110pad.h"
  52. static struct pc110pad_params default_params = {
  53. mode: PC110PAD_PS2,
  54. bounce_interval: 50 MS,
  55. tap_interval: 200 MS,
  56. irq: 10,
  57. io: 0x15E0,
  58. };
  59. static struct pc110pad_params current_params;
  60. /* driver/filesystem interface management */
  61. static wait_queue_head_t queue;
  62. static struct fasync_struct *asyncptr;
  63. static int active; /* number of concurrent open()s */
  64. static struct semaphore reader_lock;
  65. /**
  66.  * wake_readers:
  67.  *
  68.  * Take care of letting any waiting processes know that
  69.  * now would be a good time to do a read().  Called
  70.  * whenever a state transition occurs, real or synthetic. Also
  71.  * issue any SIGIO's to programs that use SIGIO on mice (eg
  72.  * Executor)
  73.  */
  74.  
  75. static void wake_readers(void)
  76. {
  77. wake_up_interruptible(&queue);
  78. kill_fasync(&asyncptr, SIGIO, POLL_IN);
  79. }
  80. /*****************************************************************************/
  81. /*
  82.  * Deal with the messy business of synthesizing button tap and drag
  83.  * events.
  84.  *
  85.  * Exports:
  86.  * notify_pad_up_down()
  87.  * Must be called whenever debounced pad up/down state changes.
  88.  * button_pending
  89.  * Flag is set whenever read_button() has new values
  90.  * to return.
  91.  * read_button()
  92.  * Obtains the current synthetic mouse button state.
  93.  */
  94. /*
  95.  * These keep track of up/down transitions needed to generate the
  96.  * synthetic mouse button events.  While recent_transition is set,
  97.  * up/down events cause transition_count to increment.  tap_timer
  98.  * turns off the recent_transition flag and may cause some synthetic
  99.  * up/down mouse events to be created by incrementing synthesize_tap.
  100.  */
  101.  
  102. static int button_pending;
  103. static int recent_transition;
  104. static int transition_count;
  105. static int synthesize_tap;
  106. static void tap_timeout(unsigned long data);
  107. static struct timer_list tap_timer = { function: tap_timeout };
  108. /**
  109.  * tap_timeout:
  110.  * @data: Unused
  111.  *
  112.  * This callback goes off a short time after an up/down transition;
  113.  * before it goes off, transitions will be considered part of a
  114.  * single PS/2 event and counted in transition_count.  Once the
  115.  * timeout occurs the recent_transition flag is cleared and
  116.  * any synthetic mouse up/down events are generated.
  117.  */
  118.  
  119. static void tap_timeout(unsigned long data)
  120. {
  121. if(!recent_transition)
  122. {
  123. printk(KERN_ERR "pc110pad: tap_timeout but no recent transition!n");
  124. }
  125. if( transition_count==2 || transition_count==4 || transition_count==6 )
  126. {
  127. synthesize_tap+=transition_count;
  128. button_pending = 1;
  129. wake_readers();
  130. }
  131. recent_transition=0;
  132. }
  133. /**
  134.  * notify_pad_up_down:
  135.  *
  136.  * Called by the raw pad read routines when a (debounced) up/down
  137.  * transition is detected.
  138.  */
  139.  
  140. void notify_pad_up_down(void)
  141. {
  142. if(recent_transition)
  143. {
  144. transition_count++;
  145. }
  146. else
  147. {
  148. transition_count=1;
  149. recent_transition=1;
  150. }
  151. mod_timer(&tap_timer, jiffies + current_params.tap_interval);
  152. /* changes to transition_count can cause reported button to change */
  153. button_pending = 1;
  154. wake_readers();
  155. }
  156. /**
  157.  * read_button:
  158.  * @b: pointer to the button status.
  159.  *
  160.  * The actual button state depends on what we are seeing. We have to check
  161.  * for the tap gesture and also for dragging.
  162.  */
  163. static void read_button(int *b)
  164. {
  165. if(synthesize_tap)
  166. {
  167. *b=--synthesize_tap & 1;
  168. }
  169. else
  170. {
  171. *b=(!recent_transition && transition_count==3); /* drag */
  172. }
  173. button_pending=(synthesize_tap>0);
  174. }
  175. /*****************************************************************************/
  176. /*
  177.  * Read pad absolute co-ordinates and debounced up/down state.
  178.  *
  179.  * Exports:
  180.  * pad_irq()
  181.  * Function to be called whenever the pad signals
  182.  * that it has new data available.
  183.  * read_raw_pad()
  184.  * Returns the most current pad state.
  185.  * xy_pending
  186.  * Flag is set whenever read_raw_pad() has new values
  187.  * to return.
  188.  * Imports:
  189.  * wake_readers()
  190.  * Called when movement occurs.
  191.  * notify_pad_up_down()
  192.  * Called when debounced up/down status changes.
  193.  */
  194. /*
  195.  * These are up/down state and absolute co-ords read directly from pad 
  196.  */
  197. static int raw_data[3];
  198. static int raw_data_count;
  199. static int raw_x, raw_y; /* most recent absolute co-ords read */
  200. static int raw_down; /* raw up/down state */
  201. static int debounced_down; /* up/down state after debounce processing */
  202. static enum { NO_BOUNCE, JUST_GONE_UP, JUST_GONE_DOWN } bounce=NO_BOUNCE;
  203. /* set just after an up/down transition */
  204. static int xy_pending; /* set if new data have not yet been read */
  205. /* 
  206.  * Timer goes off a short while after an up/down transition and copies
  207.  * the value of raw_down to debounced_down.
  208.  */
  209.  
  210. static void bounce_timeout(unsigned long data);
  211. static struct timer_list bounce_timer = { function: bounce_timeout };
  212. /**
  213.  * bounce_timeout:
  214.  * @data: Unused
  215.  *
  216.  * No further up/down transitions happened within the
  217.  * bounce period, so treat this as a genuine transition.
  218.  */
  219. static void bounce_timeout(unsigned long data)
  220. {
  221. switch(bounce)
  222. {
  223. case NO_BOUNCE:
  224. {
  225. /*
  226.  * Strange; the timer callback should only go off if
  227.  * we were expecting to do bounce processing!
  228.  */
  229. printk(KERN_WARNING "pc110pad, bounce_timeout: bounce flag not set!n");
  230. break;
  231. }
  232. case JUST_GONE_UP:
  233. {
  234. /*
  235.  * The last up we spotted really was an up, so set
  236.  * debounced state the same as raw state.
  237.  */
  238. bounce=NO_BOUNCE;
  239. if(debounced_down==raw_down)
  240. {
  241. printk(KERN_WARNING "pc110pad, bounce_timeout: raw already debounced!n");
  242. }
  243. debounced_down=raw_down;
  244. notify_pad_up_down();
  245. break;
  246. }
  247. case JUST_GONE_DOWN:
  248. {
  249. /*
  250.  * We don't debounce down events, but we still time
  251.  * out soon after one occurs so we can avoid the (x,y)
  252.  * skittering that sometimes happens.
  253.  */
  254. bounce=NO_BOUNCE;
  255. break;
  256. }
  257. }
  258. }
  259. /**
  260.  * pad_irq:
  261.  * @irq: Interrupt number
  262.  * @ptr: Unused
  263.  * @regs: Unused
  264.  *
  265.  * Callback when pad's irq goes off; copies values in to raw_* globals;
  266.  * initiates debounce processing. This isn't SMP safe however there are
  267.  * no SMP machines with a PC110 touchpad on them.
  268.  */
  269.  
  270. static void pad_irq(int irq, void *ptr, struct pt_regs *regs)
  271. {
  272. /* Obtain byte from pad and prime for next byte */
  273. {
  274. int value=inb_p(current_params.io);
  275. int handshake=inb_p(current_params.io+2);
  276. outb_p(handshake | 1, current_params.io+2);
  277. outb_p(handshake &~1, current_params.io+2);
  278. inb_p(0x64);
  279. raw_data[raw_data_count++]=value;
  280. }
  281. if(raw_data_count==3)
  282. {
  283. int new_down=raw_data[0]&0x01;
  284. int new_x=raw_data[1];
  285. int new_y=raw_data[2];
  286. if(raw_data[0]&0x10) new_x+=128;
  287. if(raw_data[0]&0x80) new_x+=256;
  288. if(raw_data[0]&0x08) new_y+=128;
  289. if( (raw_x!=new_x) || (raw_y!=new_y) )
  290. {
  291. raw_x=new_x;
  292. raw_y=new_y;
  293. xy_pending=1;
  294. }
  295. if(new_down != raw_down)
  296. {
  297. /* Down state has changed.  raw_down always holds
  298.  * the most recently observed state.
  299.  */
  300. raw_down=new_down;
  301. /* Forget any earlier bounce processing */
  302. if(bounce)
  303. {
  304. del_timer(&bounce_timer);
  305. bounce=NO_BOUNCE;
  306. }
  307. if(new_down)
  308. {
  309. if(debounced_down)
  310. {
  311. /* pad gone down, but we were reporting
  312.  * it down anyway because we suspected
  313.  * (correctly) that the last up was just
  314.  * a bounce
  315.  */
  316. }
  317. else
  318. {
  319. bounce=JUST_GONE_DOWN;
  320. mod_timer(&bounce_timer,
  321. jiffies+current_params.bounce_interval);
  322. /* start new stroke/tap */
  323. debounced_down=new_down;
  324. notify_pad_up_down();
  325. }
  326. }
  327. else /* just gone up */
  328. {
  329. if(recent_transition)
  330. {
  331. /* early bounces are probably part of
  332.  * a multi-tap gesture, so process
  333.  * immediately
  334.  */
  335. debounced_down=new_down;
  336. notify_pad_up_down();
  337. }
  338. else
  339. {
  340. /* don't trust it yet */
  341. bounce=JUST_GONE_UP;
  342. mod_timer(&bounce_timer,
  343. jiffies+current_params.bounce_interval);
  344. }
  345. }
  346. }
  347. wake_readers();
  348. raw_data_count=0;
  349. }
  350. }
  351. /**
  352.  * read_raw_pad:
  353.  * @down: set if the pen is down
  354.  * @debounced: set if the debounced pen position is down
  355.  * @x: X position
  356.  * @y: Y position
  357.  *
  358.  * Retrieve the data saved by the interrupt handler and indicate we
  359.  * have no more pending XY to do. 
  360.  *
  361.  * FIXME: We should switch to a spinlock for this.
  362.  */
  363. static void read_raw_pad(int *down, int *debounced, int *x, int *y)
  364. {
  365. disable_irq(current_params.irq);
  366. {
  367. *down=raw_down;
  368. *debounced=debounced_down;
  369. *x=raw_x;
  370. *y=raw_y;
  371. xy_pending = 0;
  372. }
  373. enable_irq(current_params.irq);
  374. }
  375. /*****************************************************************************/
  376. /*
  377.  * Filesystem interface
  378.  */
  379. /* 
  380.  * Read returns byte triples, so we need to keep track of
  381.  * how much of a triple has been read.  This is shared across
  382.  * all processes which have this device open---not that anything
  383.  * will make much sense in that case.
  384.  */
  385. static int read_bytes[3];
  386. static int read_byte_count;
  387. /**
  388.  * sample_raw:
  389.  * @d: sample buffer
  390.  *
  391.  * Retrieve a triple of sample data. 
  392.  */
  393. static void sample_raw(int d[3])
  394. {
  395. d[0]=raw_data[0];
  396. d[1]=raw_data[1];
  397. d[2]=raw_data[2];
  398. }
  399. /**
  400.  * sample_rare:
  401.  * @d: sample buffer
  402.  *
  403.  * Retrieve a triple of sample data and sanitize it. We do the needed
  404.  * scaling and masking to get the current status.
  405.  */
  406. static void sample_rare(int d[3])
  407. {
  408. int thisd, thisdd, thisx, thisy;
  409. read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
  410. d[0]=(thisd?0x80:0)
  411.    | (thisx/256)<<4
  412.    | (thisdd?0x08:0)
  413.    | (thisy/256)
  414. ;
  415. d[1]=thisx%256;
  416. d[2]=thisy%256;
  417. }
  418. /**
  419.  * sample_debug:
  420.  * @d: sample buffer
  421.  *
  422.  * Retrieve a triple of sample data and mix it up with the state 
  423.  * information in the gesture parser. Not useful for normal users but
  424.  * handy when debugging
  425.  */
  426. static void sample_debug(int d[3])
  427. {
  428. int thisd, thisdd, thisx, thisy;
  429. int b;
  430. unsigned long flags;
  431. save_flags(flags);
  432. cli();
  433. read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
  434. d[0]=(thisd?0x80:0) | (thisdd?0x40:0) | bounce;
  435. d[1]=(recent_transition?0x80:0)+transition_count;
  436. read_button(&b);
  437. d[2]=(synthesize_tap<<4) | (b?0x01:0);
  438. restore_flags(flags);
  439. }
  440. /**
  441.  * sample_ps2:
  442.  * @d: sample buffer
  443.  *
  444.  * Retrieve a triple of sample data and turn the debounced tap and
  445.  * stroke information into what appears to be a PS/2 mouse. This means
  446.  * the PC110 pad needs no funny application side support.
  447.  */
  448. static void sample_ps2(int d[3])
  449. {
  450. static int lastx, lasty, lastd;
  451. int thisd, thisdd, thisx, thisy;
  452. int dx, dy, b;
  453. /*
  454.  * Obtain the current mouse parameters and limit as appropriate for
  455.  * the return data format.  Interrupts are only disabled while 
  456.  * obtaining the parameters, NOT during the puts_fs_byte() calls,
  457.  * so paging in put_user() does not affect mouse tracking.
  458.  */
  459. read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
  460. read_button(&b);
  461. /* Now compare with previous readings.  Note that we use the
  462.  * raw down flag rather than the debounced one.
  463.  */
  464. if( (thisd && !lastd) /* new stroke */
  465.  || (bounce!=NO_BOUNCE) )
  466. {
  467. dx=0;
  468. dy=0;
  469. }
  470. else
  471. {
  472. dx =  (thisx-lastx);
  473. dy = -(thisy-lasty);
  474. }
  475. lastx=thisx;
  476. lasty=thisy;
  477. lastd=thisd;
  478. /*
  479. d[0]= ((dy<0)?0x20:0)
  480.     | ((dx<0)?0x10:0)
  481.     | 0x08
  482.     | (b? 0x01:0x00)
  483. ;
  484. */
  485. d[0]= ((dy<0)?0x20:0)
  486.     | ((dx<0)?0x10:0)
  487.     | (b? 0x00:0x08)
  488. ;
  489. d[1]=dx;
  490. d[2]=dy;
  491. }
  492. /**
  493.  * fasync_pad:
  494.  * @fd: file number for the file 
  495.  * @filp: file handle
  496.  * @on: 1 to add, 0 to remove a notifier
  497.  *
  498.  * Update the queue of asynchronous event notifiers. We can use the
  499.  * same helper the mice do and that does almost everything we need.
  500.  */
  501.  
  502. static int fasync_pad(int fd, struct file *filp, int on)
  503. {
  504. int retval;
  505. retval = fasync_helper(fd, filp, on, &asyncptr);
  506. if (retval < 0)
  507. return retval;
  508. return 0;
  509. }
  510. /**
  511.  * close_pad:
  512.  * @inode: inode of pad
  513.  * @file: file handle to pad
  514.  *
  515.  * Close access to the pad. We turn the pad power off if this is the
  516.  * last user of the pad. I've not actually measured the power draw but
  517.  * the DOS driver is careful to do this so we follow suit.
  518.  */
  519.  
  520. static int close_pad(struct inode * inode, struct file * file)
  521. {
  522. lock_kernel();
  523. fasync_pad(-1, file, 0);
  524. if (!--active)
  525. outb(0x30, current_params.io+2);  /* switch off digitiser */
  526. unlock_kernel();
  527. return 0;
  528. }
  529. /**
  530.  * open_pad:
  531.  * @inode: inode of pad
  532.  * @file: file handle to pad
  533.  *
  534.  * Open access to the pad. We turn the pad off first (we turned it off
  535.  * on close but if this is the first open after a crash the state is
  536.  * indeterminate). The device has a small fifo so we empty that before
  537.  * we kick it back into action.
  538.  */
  539.  
  540. static int open_pad(struct inode * inode, struct file * file)
  541. {
  542. unsigned long flags;
  543. if (active++)
  544. return 0;
  545. save_flags(flags);
  546. cli();
  547. outb(0x30, current_params.io+2); /* switch off digitiser */
  548. pad_irq(0,0,0); /* read to flush any pending bytes */
  549. pad_irq(0,0,0); /* read to flush any pending bytes */
  550. pad_irq(0,0,0); /* read to flush any pending bytes */
  551. outb(0x38, current_params.io+2); /* switch on digitiser */
  552. current_params = default_params;
  553. raw_data_count=0; /* re-sync input byte counter */
  554. read_byte_count=0; /* re-sync output byte counter */
  555. button_pending=0;
  556. recent_transition=0;
  557. transition_count=0;
  558. synthesize_tap=0;
  559. del_timer(&bounce_timer);
  560. del_timer(&tap_timer);
  561. restore_flags(flags);
  562. return 0;
  563. }
  564. /**
  565.  * write_pad:
  566.  * @file: File handle to the pad
  567.  * @buffer: Unused
  568.  * @count: Unused
  569.  * @ppos: Unused
  570.  *
  571.  * Writes are disallowed. A true PS/2 mouse lets you write stuff. Everyone
  572.  * seems happy with this and not faking the write modes.
  573.  */
  574. static ssize_t write_pad(struct file * file, const char * buffer, size_t count, loff_t *ppos)
  575. {
  576. return -EINVAL;
  577. }
  578. /*
  579.  * new_sample:
  580.  * @d: sample buffer
  581.  *
  582.  * Fetch a new sample according the current mouse mode the pad is 
  583.  * using.
  584.  */
  585.  
  586. void new_sample(int d[3])
  587. {
  588. switch(current_params.mode)
  589. {
  590. case PC110PAD_RAW: sample_raw(d); break;
  591. case PC110PAD_RARE: sample_rare(d); break;
  592. case PC110PAD_DEBUG: sample_debug(d); break;
  593. case PC110PAD_PS2: sample_ps2(d); break;
  594. }
  595. }
  596. /**
  597.  * read_pad:
  598.  * @file: File handle to pad
  599.  * @buffer: Target for the mouse data
  600.  * @count: Buffer length
  601.  * @ppos: Offset (unused)
  602.  *
  603.  * Read data from the pad. We use the reader_lock to avoid mess when there are
  604.  * two readers. This shouldnt be happening anyway but we play safe.
  605.  */
  606.  
  607. static ssize_t read_pad(struct file * file, char * buffer, size_t count, loff_t *ppos)
  608. {
  609. int r;
  610. down(&reader_lock);
  611. for(r=0; r<count; r++)
  612. {
  613. if(!read_byte_count)
  614. new_sample(read_bytes);
  615. if(put_user(read_bytes[read_byte_count], buffer+r))
  616. {
  617. r = -EFAULT;
  618. break;
  619. }
  620. read_byte_count = (read_byte_count+1)%3;
  621. }
  622. up(&reader_lock);
  623. return r;
  624. }
  625. /**
  626.  * pad_poll:
  627.  * @file: File of the pad device
  628.  * @wait: Poll table
  629.  *
  630.  * The pad is ready to read if there is a button or any position change
  631.  * pending in the queue. The reading and interrupt routines maintain the
  632.  * required state for us and do needed wakeups.
  633.  */
  634. static unsigned int pad_poll(struct file *file, poll_table * wait)
  635. {
  636. poll_wait(file, &queue, wait);
  637.      if(button_pending || xy_pending)
  638. return POLLIN | POLLRDNORM;
  639. return 0;
  640. }
  641. /**
  642.  * pad_ioctl;
  643.  * @inode: Inode of the pad
  644.  * @file: File handle to the pad
  645.  * @cmd: Ioctl command
  646.  * @arg: Argument pointer
  647.  *
  648.  * The PC110 pad supports two ioctls both of which use the pc110pad_params
  649.  * structure. GETP queries the current pad status. SETP changes the pad
  650.  * configuration. Changing configuration during normal mouse operations
  651.  * may give momentarily odd results as things like tap gesture state
  652.  * may be lost.
  653.  */
  654.  
  655. static int pad_ioctl(struct inode *inode, struct file * file,
  656. unsigned int cmd, unsigned long arg)
  657. {
  658. struct pc110pad_params new;
  659. if (!inode)
  660. return -EINVAL;
  661. switch (cmd) {
  662. case PC110PADIOCGETP:
  663. new = current_params;
  664. if(copy_to_user((void *)arg, &new, sizeof(new)))
  665. return -EFAULT;
  666. return 0;
  667. case PC110PADIOCSETP:
  668. if(copy_from_user(&new, (void *)arg, sizeof(new)))
  669. return -EFAULT;
  670. if( (new.mode<PC110PAD_RAW)
  671.  || (new.mode>PC110PAD_PS2)
  672.  || (new.bounce_interval<0)
  673.  || (new.tap_interval<0)
  674. )
  675. return -EINVAL;
  676. current_params.mode = new.mode;
  677. current_params.bounce_interval = new.bounce_interval;
  678. current_params.tap_interval = new.tap_interval;
  679. return 0;
  680. }
  681. return -ENOTTY;
  682. }
  683. static struct file_operations pad_fops = {
  684. owner: THIS_MODULE,
  685. read: read_pad,
  686. write: write_pad,
  687. poll: pad_poll,
  688. ioctl: pad_ioctl,
  689. open: open_pad,
  690. release: close_pad,
  691. fasync: fasync_pad,
  692. };
  693. static struct miscdevice pc110_pad = {
  694. minor: PC110PAD_MINOR,
  695. name: "pc110 pad",
  696. fops: &pad_fops,
  697. };
  698. /**
  699.  * pc110pad_init_driver:
  700.  *
  701.  * We configure the pad with the default parameters (that is PS/2 
  702.  * emulation mode. We then claim the needed I/O and interrupt resources.
  703.  * Finally as a matter of paranoia we turn the pad off until we are
  704.  * asked to open it by an application.
  705.  */
  706. static char banner[] __initdata = KERN_INFO "PC110 digitizer pad at 0x%X, irq %d.n";
  707. static int __init pc110pad_init_driver(void)
  708. {
  709. init_MUTEX(&reader_lock);
  710. current_params = default_params;
  711. if (request_irq(current_params.irq, pad_irq, 0, "pc110pad", 0)) {
  712. printk(KERN_ERR "pc110pad: Unable to get IRQ.n");
  713. return -EBUSY;
  714. }
  715. if (!request_region(current_params.io, 4, "pc110pad")) {
  716. printk(KERN_ERR "pc110pad: I/O area in use.n");
  717. free_irq(current_params.irq,0);
  718. return -EBUSY;
  719. }
  720. init_waitqueue_head(&queue);
  721. printk(banner, current_params.io, current_params.irq);
  722. misc_register(&pc110_pad);
  723. outb(0x30, current_params.io+2); /* switch off digitiser */
  724. return 0;
  725. }
  726. /*
  727.  * pc110pad_exit_driver:
  728.  *
  729.  * Free the resources we acquired when the module was loaded. We also
  730.  * turn the pad off to be sure we don't leave it using power.
  731.  */
  732. static void __exit pc110pad_exit_driver(void)
  733. {
  734. outb(0x30, current_params.io+2); /* switch off digitiser */
  735. if (current_params.irq)
  736. free_irq(current_params.irq, 0);
  737. current_params.irq = 0;
  738. release_region(current_params.io, 4);
  739. misc_deregister(&pc110_pad);
  740. }
  741. module_init(pc110pad_init_driver);
  742. module_exit(pc110pad_exit_driver);
  743. MODULE_AUTHOR("Alan Cox, Robin O'Leary");
  744. MODULE_DESCRIPTION("Driver for the touchpad on the IBM PC110 palmtop");
  745. MODULE_LICENSE("GPL");
  746. EXPORT_NO_SYMBOLS;